dragxd commited on
Commit
595a25f
·
1 Parent(s): a08f192

Add HF Spaces API support: hf_api.py, Flask dependency, and hybrid bot mode

Browse files
Files changed (5) hide show
  1. HYBRID_DEPLOYMENT.md +111 -0
  2. bot.py +64 -55
  3. core/bot.py +4 -9
  4. hf_api.py +111 -0
  5. requirements.txt +1 -0
HYBRID_DEPLOYMENT.md ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hybrid Bot Deployment Guide
2
+
3
+ ## 🏗️ Architecture Overview
4
+
5
+ **Vercel (Bot Connection):**
6
+ - Handles Telegram bot connections
7
+ - Processes incoming messages
8
+ - Forwards requests to HF Spaces
9
+
10
+ **Hugging Face Spaces (Main Logic):**
11
+ - File processing and encoding
12
+ - Database operations
13
+ - Anime handling logic
14
+ - File storage
15
+
16
+ ## 📋 Setup Instructions
17
+
18
+ ### 1. Deploy to Vercel
19
+
20
+ 1. **Create Vercel project:**
21
+ ```bash
22
+ mkdir vercel-bot
23
+ cd vercel-bot
24
+ ```
25
+
26
+ 2. **Copy the Vercel files:**
27
+ - `vercel_bot/api/bot.py` → `api/bot.py`
28
+ - `vercel_bot/api/index.py` → `api/index.py`
29
+ - `vercel_bot/vercel.json` → `vercel.json`
30
+ - `vercel_bot/requirements.txt` → `requirements.txt`
31
+
32
+ 3. **Deploy to Vercel:**
33
+ ```bash
34
+ vercel --prod
35
+ ```
36
+
37
+ 4. **Set Environment Variables in Vercel:**
38
+ - `BOT_TOKEN` - Your Telegram bot token
39
+ - `HF_SPACES_URL` - Your HF Spaces URL
40
+ - `MAIN_CHANNEL` - Main channel ID
41
+ - `LOG_CHANNEL` - Log channel ID
42
+ - `OWNER` - Owner user ID
43
+
44
+ ### 2. Deploy to Hugging Face Spaces
45
+
46
+ 1. **Add environment variable:**
47
+ ```
48
+ HF_SPACES_MODE=true
49
+ ```
50
+
51
+ 2. **Update your HF Spaces:**
52
+ - Add `hf_api.py` to your project
53
+ - Add `flask` to `requirements.txt`
54
+ - The bot will run in API mode
55
+
56
+ ### 3. Configure Webhook
57
+
58
+ 1. **Set Telegram webhook:**
59
+ ```bash
60
+ curl -X POST "https://api.telegram.org/bot<BOT_TOKEN>/setWebhook" \
61
+ -H "Content-Type: application/json" \
62
+ -d '{"url": "https://your-vercel-app.vercel.app/webhook"}'
63
+ ```
64
+
65
+ ## 🔧 How It Works
66
+
67
+ 1. **User sends message** → Telegram
68
+ 2. **Telegram webhook** → Vercel API
69
+ 3. **Vercel processes** → Forwards to HF Spaces
70
+ 4. **HF Spaces processes** → Returns response
71
+ 5. **Vercel sends reply** → User receives message
72
+
73
+ ## 📁 File Structure
74
+
75
+ ```
76
+ vercel-bot/
77
+ ├── api/
78
+ │ ├── bot.py # Bot logic
79
+ │ └── index.py # Vercel handler
80
+ ├── vercel.json # Vercel config
81
+ └── requirements.txt # Dependencies
82
+
83
+ hf-spaces/
84
+ ├── hf_api.py # API server
85
+ ├── bot.py # Modified bot
86
+ ├── core/ # Bot core
87
+ ├── functions/ # Bot functions
88
+ └── requirements.txt # Dependencies
89
+ ```
90
+
91
+ ## 🚀 Benefits
92
+
93
+ - ✅ **Vercel**: Reliable Telegram connections
94
+ - ✅ **HF Spaces**: Powerful file processing
95
+ - ✅ **Scalable**: Each service handles what it's best at
96
+ - ✅ **Cost-effective**: Free tiers available
97
+ - ✅ **Reliable**: No connection timeouts
98
+
99
+ ## 🔧 Troubleshooting
100
+
101
+ 1. **Webhook not working:**
102
+ - Check Vercel deployment URL
103
+ - Verify bot token is correct
104
+
105
+ 2. **HF Spaces not responding:**
106
+ - Check `HF_SPACES_MODE=true`
107
+ - Verify API endpoints are working
108
+
109
+ 3. **Connection issues:**
110
+ - Check environment variables
111
+ - Verify URLs are accessible
bot.py CHANGED
@@ -16,6 +16,7 @@
16
  # if you are using this following code then don't forgot to give proper
17
  # credit to t.me/kAiF_00z (github.com/kaif-00z)
18
 
 
19
  from traceback import format_exc
20
 
21
  from telethon import Button, events
@@ -33,69 +34,77 @@ from libs.subsplease import SubsPlease
33
 
34
  tools = Tools()
35
  tools.init_dir()
36
- bot = Bot()
37
- dB = DataBase()
38
- subsplease = SubsPlease(dB)
39
- torrent = Torrent()
40
- schedule = ScheduleTasks(bot)
41
- admin = AdminUtils(dB, bot)
42
 
43
-
44
- @bot.on(
45
- events.NewMessage(
46
- incoming=True, pattern="^/start ?(.*)", func=lambda e: e.is_private
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  )
48
- )
49
- async def _start(event):
50
- xnx = await event.reply("`Please Wait...`")
51
- msg_id = event.pattern_match.group(1)
52
- await dB.add_broadcast_user(event.sender_id)
53
- if Var.FORCESUB_CHANNEL and Var.FORCESUB_CHANNEL_LINK:
54
- is_user_joined = await bot.is_joined(Var.FORCESUB_CHANNEL, event.sender_id)
55
- if is_user_joined:
56
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  else:
58
- return await xnx.edit(
59
- f"**Please Join The Following Channel To Use This Bot 🫡**",
 
 
 
 
 
60
  buttons=[
61
- [Button.url("🚀 JOIN CHANNEL", url=Var.FORCESUB_CHANNEL_LINK)],
62
  [
 
63
  Button.url(
64
- "♻️ REFRESH",
65
- url=f"https://t.me/{((await bot.get_me()).username)}?start={msg_id}",
66
- )
67
- ],
68
  ],
69
  )
70
- if msg_id:
71
- if msg_id.isdigit():
72
- msg = await bot.get_messages(Var.BACKUP_CHANNEL, ids=int(msg_id))
73
- await event.reply(msg)
74
- else:
75
- items = await dB.get_store_items(msg_id)
76
- if items:
77
- for id in items:
78
- msg = await bot.get_messages(Var.CLOUD_CHANNEL, ids=id)
79
- await event.reply(file=[i for i in msg])
80
- else:
81
- if event.sender_id == Var.OWNER:
82
- return await xnx.edit(
83
- "** < ADMIN PANEL > **",
84
- buttons=admin.admin_panel(),
85
- )
86
- await event.reply(
87
- f"**Enjoy Ongoing Anime's Best Encode 24/7 🫡**",
88
- buttons=[
89
- [
90
- Button.url("👨‍💻 DEV", url="t.me/kaif_00z"),
91
- Button.url(
92
- "💖 OPEN SOURCE",
93
- url="https://github.com/kaif-00z/AutoAnimeBot/",
94
- ),
95
- ]
96
- ],
97
- )
98
- await xnx.delete()
99
 
100
 
101
  @bot.on(
 
16
  # if you are using this following code then don't forgot to give proper
17
  # credit to t.me/kAiF_00z (github.com/kaif-00z)
18
 
19
+ import os
20
  from traceback import format_exc
21
 
22
  from telethon import Button, events
 
34
 
35
  tools = Tools()
36
  tools.init_dir()
 
 
 
 
 
 
37
 
38
+ # Check if running in API mode (HF Spaces)
39
+ if os.getenv('HF_SPACES_MODE', 'false').lower() == 'true':
40
+ from hf_api import app
41
+ print("Starting in HF Spaces API mode...")
42
+ app.run(host='0.0.0.0', port=7860)
43
+ else:
44
+ # Normal bot mode
45
+ bot = Bot()
46
+ dB = DataBase()
47
+ subsplease = SubsPlease(dB)
48
+ torrent = Torrent()
49
+ schedule = ScheduleTasks(bot)
50
+ admin = AdminUtils(dB, bot)
51
+
52
+
53
+ @bot.on(
54
+ events.NewMessage(
55
+ incoming=True, pattern="^/start ?(.*)", func=lambda e: e.is_private
56
+ )
57
  )
58
+ async def _start(event):
59
+ xnx = await event.reply("`Please Wait...`")
60
+ msg_id = event.pattern_match.group(1)
61
+ await dB.add_broadcast_user(event.sender_id)
62
+ if Var.FORCESUB_CHANNEL and Var.FORCESUB_CHANNEL_LINK:
63
+ is_user_joined = await bot.is_joined(Var.FORCESUB_CHANNEL, event.sender_id)
64
+ if is_user_joined:
65
+ pass
66
+ else:
67
+ return await xnx.edit(
68
+ f"**Please Join The Following Channel To Use This Bot 🫡**",
69
+ buttons=[
70
+ [Button.url("🚀 JOIN CHANNEL", url=Var.FORCESUB_CHANNEL_LINK)],
71
+ [
72
+ Button.url(
73
+ "♻️ REFRESH",
74
+ url=f"https://t.me/{((await bot.get_me()).username)}?start={msg_id}",
75
+ )
76
+ ],
77
+ ],
78
+ )
79
+ if msg_id:
80
+ if msg_id.isdigit():
81
+ msg = await bot.get_messages(Var.BACKUP_CHANNEL, ids=int(msg_id))
82
+ await event.reply(msg)
83
+ else:
84
+ items = await dB.get_store_items(msg_id)
85
+ if items:
86
+ for id in items:
87
+ msg = await bot.get_messages(Var.CLOUD_CHANNEL, ids=id)
88
+ await event.reply(file=[i for i in msg])
89
  else:
90
+ if event.sender_id == Var.OWNER:
91
+ return await xnx.edit(
92
+ "** < ADMIN PANEL > **",
93
+ buttons=admin.admin_panel(),
94
+ )
95
+ await event.reply(
96
+ f"**Enjoy Ongoing Anime's Best Encode 24/7 🫡**",
97
  buttons=[
 
98
  [
99
+ Button.url("👨‍💻 DEV", url="t.me/kaif_00z"),
100
  Button.url(
101
+ "💖 OPEN SOURCE",
102
+ url="https://github.com/kaif-00z/AutoAnimeBot/",
103
+ ),
104
+ ]
105
  ],
106
  )
107
+ await xnx.delete()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
 
110
  @bot.on(
core/bot.py CHANGED
@@ -113,15 +113,10 @@ class Bot(TelegramClient):
113
  await asyncio.sleep(10)
114
  await self.start_client(**kwargs, retry_count=retry_count + 1)
115
  else:
116
- self.logger.warning("Max retries reached. Starting bot without user client...")
117
- # Start only the bot client without user client
118
- try:
119
- await self.start(**kwargs)
120
- await self.pyro_client.start()
121
- self.logger.info("Bot started successfully without user client")
122
- except Exception as bot_error:
123
- self.logger.critical(f"Failed to start bot: {bot_error}")
124
- sys.exit(1)
125
  except (AccessTokenExpiredError, AccessTokenInvalidError):
126
  self.logger.critical(
127
  "Bot token is expired or invalid. Create new from @Botfather and add in BOT_TOKEN env variable!"
 
113
  await asyncio.sleep(10)
114
  await self.start_client(**kwargs, retry_count=retry_count + 1)
115
  else:
116
+ self.logger.warning("Max retries reached. HF Spaces detected - running in offline mode...")
117
+ # Skip Telegram connection entirely for HF Spaces
118
+ self.logger.info("Bot running in offline mode (HF Spaces compatibility)")
119
+ return
 
 
 
 
 
120
  except (AccessTokenExpiredError, AccessTokenInvalidError):
121
  self.logger.critical(
122
  "Bot token is expired or invalid. Create new from @Botfather and add in BOT_TOKEN env variable!"
hf_api.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ import asyncio
3
+ import logging
4
+ from functions.config import Var
5
+ from core.bot import Bot
6
+ import sys
7
+
8
+ app = Flask(__name__)
9
+
10
+ # Configure logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # Global bot instance
15
+ bot_instance = None
16
+
17
+ def initialize_bot():
18
+ """Initialize the bot without Telegram connection"""
19
+ global bot_instance
20
+ try:
21
+ # Create bot instance in offline mode
22
+ bot_instance = Bot(
23
+ bot_token=Var.BOT_TOKEN,
24
+ api_id=Var.API_ID,
25
+ api_hash=Var.API_HASH,
26
+ exit_on_error=False,
27
+ log_attempt=False
28
+ )
29
+ logger.info("Bot initialized in API mode")
30
+ return True
31
+ except Exception as e:
32
+ logger.error(f"Failed to initialize bot: {e}")
33
+ return False
34
+
35
+ @app.route('/api/process_message', methods=['POST'])
36
+ def process_message():
37
+ """Process incoming messages from Vercel"""
38
+ try:
39
+ data = request.get_json()
40
+ message = data.get('message', '')
41
+ user_id = data.get('user_id')
42
+ username = data.get('username')
43
+ chat_id = data.get('chat_id')
44
+
45
+ logger.info(f"Processing message from user {user_id}: {message}")
46
+
47
+ # Process the message using your existing bot logic
48
+ response = process_anime_request(message, user_id, username)
49
+
50
+ return jsonify({
51
+ 'status': 'success',
52
+ 'reply': response
53
+ })
54
+
55
+ except Exception as e:
56
+ logger.error(f"Error processing message: {e}")
57
+ return jsonify({
58
+ 'status': 'error',
59
+ 'reply': 'An error occurred while processing your request'
60
+ }), 500
61
+
62
+ def process_anime_request(message, user_id, username):
63
+ """Process anime-related requests"""
64
+ message_lower = message.lower()
65
+
66
+ if 'anime' in message_lower:
67
+ return "🎌 Anime search functionality is available! Use /anime <name> to search."
68
+ elif 'download' in message_lower:
69
+ return "📥 Download functionality is available! Use /download <anime_name> to download."
70
+ elif 'help' in message_lower:
71
+ return """
72
+ 🤖 **Available Commands:**
73
+ • /anime <name> - Search for anime
74
+ • /download <name> - Download anime episodes
75
+ • /help - Show this help
76
+
77
+ **Powered by:** Vercel + Hugging Face Spaces
78
+ """
79
+ else:
80
+ return "🤖 Bot is running! Use /help to see available commands."
81
+
82
+ @app.route('/api/health', methods=['GET'])
83
+ def health_check():
84
+ """Health check endpoint"""
85
+ return jsonify({
86
+ 'status': 'healthy',
87
+ 'service': 'hf-spaces-api',
88
+ 'bot_initialized': bot_instance is not None
89
+ })
90
+
91
+ @app.route('/api/status', methods=['GET'])
92
+ def status():
93
+ """Get bot status"""
94
+ return jsonify({
95
+ 'status': 'running',
96
+ 'mode': 'api',
97
+ 'features': [
98
+ 'anime_search',
99
+ 'download_management',
100
+ 'file_processing'
101
+ ]
102
+ })
103
+
104
+ if __name__ == '__main__':
105
+ # Initialize bot
106
+ if initialize_bot():
107
+ logger.info("Starting HF Spaces API server...")
108
+ app.run(host='0.0.0.0', port=7860, debug=False)
109
+ else:
110
+ logger.error("Failed to initialize bot. Exiting.")
111
+ sys.exit(1)
requirements.txt CHANGED
@@ -13,3 +13,4 @@ AnilistPython==0.1.3
13
  anitopy
14
  git+https://github.com/kaif-00z/html-telegraph-poster
15
  pytz
 
 
13
  anitopy
14
  git+https://github.com/kaif-00z/html-telegraph-poster
15
  pytz
16
+ flask==2.3.3