Hiren122 commited on
Commit
3bbd110
Β·
verified Β·
1 Parent(s): 8b9d70f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +225 -0
app.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ bot.py – Telegram bot for Frenix API key generation (free tier only).
3
+
4
+ Setup:
5
+ 1. pip install python-telegram-bot requests python-dotenv
6
+ 2. Set BOT_TOKEN and API_BASE_URL in your .env or environment:
7
+ BOT_TOKEN=<your Telegram bot token from @BotFather>
8
+ API_BASE_URL=https://your-vercel-app.vercel.app (or http://localhost:5000)
9
+ 3. python bot.py
10
+
11
+ The bot will:
12
+ - Ask the user for their first name, last name, and username
13
+ - Call POST /v1/api-keys on your Frenix API server
14
+ - Return the generated free-tier API key
15
+ """
16
+
17
+ import os
18
+ import logging
19
+ import requests
20
+ from dotenv import load_dotenv
21
+ from telegram import Update, ReplyKeyboardRemove
22
+ from telegram.ext import (
23
+ ApplicationBuilder,
24
+ CommandHandler,
25
+ MessageHandler,
26
+ ConversationHandler,
27
+ ContextTypes,
28
+ filters,
29
+ )
30
+
31
+ load_dotenv()
32
+
33
+ # ── Config ────────────────────────────────────────────────────────────────────
34
+ BOT_TOKEN = os.environ.get("BOT_TOKEN", "8388247852:AAEAfqWAB0selpoWGt6WzzuhkpK-VCU4ES4")
35
+ API_BASE_URL = os.environ.get("API_BASE_URL", "https://api.frenix.sh").rstrip("/")
36
+
37
+ if not BOT_TOKEN:
38
+ raise RuntimeError("BOT_TOKEN is not set. Add it to your .env file.")
39
+
40
+ logging.basicConfig(
41
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
42
+ level=logging.INFO,
43
+ )
44
+ log = logging.getLogger(__name__)
45
+
46
+ # ── Conversation states ───────────────────────────────────────────────────────
47
+ FIRST_NAME, LAST_NAME, USERNAME_INPUT = range(3)
48
+
49
+
50
+ # ── Helpers ───────────────────────────────────────────────────────────────────
51
+
52
+ def _create_api_key(user_id: str, username: str, first_name: str, last_name: str) -> dict:
53
+ """Call POST /v1/api-keys and return the JSON response."""
54
+ url = f"{API_BASE_URL}/v1/api-keys"
55
+ payload = {
56
+ "user_id": str(user_id),
57
+ "username": username,
58
+ "first_name": first_name,
59
+ "last_name": last_name,
60
+ }
61
+ try:
62
+ resp = requests.post(url, json=payload, timeout=15)
63
+ return resp.json()
64
+ except requests.exceptions.ConnectionError:
65
+ return {"error": f"Could not connect to the API server at {API_BASE_URL}"}
66
+ except Exception as e:
67
+ return {"error": str(e)}
68
+
69
+
70
+ # ── Handlers ──────────────────────────────────────────────────────────────────
71
+
72
+ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
73
+ """Entry point – /start command."""
74
+ user = update.effective_user
75
+ await update.message.reply_text(
76
+ f"πŸ‘‹ Hello, {user.first_name}!\n\n"
77
+ "Welcome to *Frenix API* key generator.\n"
78
+ "I'll create a *free-tier* API key for you in just a few steps.\n\n"
79
+ "What is your *first name*? (or /cancel to abort)",
80
+ parse_mode="Markdown",
81
+ reply_markup=ReplyKeyboardRemove(),
82
+ )
83
+ return FIRST_NAME
84
+
85
+
86
+ async def get_first_name(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
87
+ """Store first name and ask for last name."""
88
+ context.user_data["first_name"] = update.message.text.strip()
89
+ await update.message.reply_text(
90
+ "Great! Now enter your *last name*:",
91
+ parse_mode="Markdown",
92
+ )
93
+ return LAST_NAME
94
+
95
+
96
+ async def get_last_name(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
97
+ """Store last name and ask for username."""
98
+ context.user_data["last_name"] = update.message.text.strip()
99
+ await update.message.reply_text(
100
+ "Almost done! Enter your preferred *username* (no spaces, e.g. john_doe):",
101
+ parse_mode="Markdown",
102
+ )
103
+ return USERNAME_INPUT
104
+
105
+
106
+ async def get_username(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
107
+ """Store username, call the API, and return the key."""
108
+ tg_user = update.effective_user
109
+ first_name = context.user_data.get("first_name", "")
110
+ last_name = context.user_data.get("last_name", "")
111
+ username = update.message.text.strip().replace(" ", "_")
112
+
113
+ await update.message.reply_text("⏳ Generating your API key, please wait…")
114
+
115
+ result = _create_api_key(
116
+ user_id = tg_user.id,
117
+ username = username,
118
+ first_name = first_name,
119
+ last_name = last_name,
120
+ )
121
+
122
+ if "error" in result:
123
+ await update.message.reply_text(
124
+ f"❌ Error: {result['error']}\n\nPlease try again with /start.",
125
+ )
126
+ return ConversationHandler.END
127
+
128
+ api_key = result.get("api_key", "N/A")
129
+ plan = result.get("plan", "free")
130
+ rpm = result.get("limits", {}).get("rpm", "?")
131
+ message = result.get("message", "")
132
+
133
+ await update.message.reply_text(
134
+ f"βœ… *Your Frenix API Key is ready!*\n\n"
135
+ f"```\n{api_key}\n```\n\n"
136
+ f"πŸ“‹ *Details:*\n"
137
+ f"β€’ Plan: `{plan}`\n"
138
+ f"β€’ Rate limit: `{rpm}` requests/min\n"
139
+ f"β€’ Name: `{first_name} {last_name}`\n"
140
+ f"β€’ Username: `{username}`\n\n"
141
+ f"ℹ️ {message}\n\n"
142
+ f"πŸ”— *Base URL:* `{API_BASE_URL}/v1`\n\n"
143
+ f"Use this key as your `Authorization: Bearer <key>` header.\n"
144
+ f"Type /start to generate another key.",
145
+ parse_mode="Markdown",
146
+ )
147
+ return ConversationHandler.END
148
+
149
+
150
+ async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
151
+ """Cancel the conversation."""
152
+ await update.message.reply_text(
153
+ "❌ Cancelled. Type /start whenever you want a new API key.",
154
+ reply_markup=ReplyKeyboardRemove(),
155
+ )
156
+ return ConversationHandler.END
157
+
158
+
159
+ async def mykey(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
160
+ """/mykey – retrieve existing key for this Telegram user."""
161
+ tg_user = update.effective_user
162
+ result = _create_api_key(
163
+ user_id = tg_user.id,
164
+ username = tg_user.username or "",
165
+ first_name = tg_user.first_name or "",
166
+ last_name = tg_user.last_name or "",
167
+ )
168
+ if "error" in result:
169
+ await update.message.reply_text(f"❌ Error: {result['error']}")
170
+ return
171
+
172
+ api_key = result.get("api_key", "N/A")
173
+ plan = result.get("plan", "free")
174
+ rpm = result.get("limits", {}).get("rpm", "?")
175
+ message = result.get("message", "")
176
+
177
+ await update.message.reply_text(
178
+ f"πŸ”‘ *Your Frenix API Key:*\n\n"
179
+ f"```\n{api_key}\n```\n\n"
180
+ f"β€’ Plan: `{plan}`\n"
181
+ f"β€’ Rate limit: `{rpm}` req/min\n\n"
182
+ f"ℹ️ {message}",
183
+ parse_mode="Markdown",
184
+ )
185
+
186
+
187
+ async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
188
+ """/help command."""
189
+ await update.message.reply_text(
190
+ "πŸ€– *Frenix API Bot*\n\n"
191
+ "Commands:\n"
192
+ "β€’ /start – Generate a new free-tier API key\n"
193
+ "β€’ /mykey – Retrieve your existing API key\n"
194
+ "β€’ /help – Show this help message\n"
195
+ "β€’ /cancel – Cancel current operation\n\n"
196
+ f"πŸ”— API Base URL: `{API_BASE_URL}/v1`",
197
+ parse_mode="Markdown",
198
+ )
199
+
200
+
201
+ # ── Main ──────────────────────────────────────────────────────────────────────
202
+
203
+ def main():
204
+ app = ApplicationBuilder().token(BOT_TOKEN).build()
205
+
206
+ conv_handler = ConversationHandler(
207
+ entry_points=[CommandHandler("start", start)],
208
+ states={
209
+ FIRST_NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, get_first_name)],
210
+ LAST_NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, get_last_name)],
211
+ USERNAME_INPUT: [MessageHandler(filters.TEXT & ~filters.COMMAND, get_username)],
212
+ },
213
+ fallbacks=[CommandHandler("cancel", cancel)],
214
+ )
215
+
216
+ app.add_handler(conv_handler)
217
+ app.add_handler(CommandHandler("mykey", mykey))
218
+ app.add_handler(CommandHandler("help", help_cmd))
219
+
220
+ log.info(f"Bot started. API server: {API_BASE_URL}")
221
+ app.run_polling(allowed_updates=Update.ALL_TYPES)
222
+
223
+
224
+ if __name__ == "__main__":
225
+ main()