Update main.py
Browse files
main.py
CHANGED
|
@@ -3,87 +3,92 @@ import threading
|
|
| 3 |
import random
|
| 4 |
import aiohttp
|
| 5 |
import requests
|
|
|
|
|
|
|
| 6 |
import traceback
|
| 7 |
import asyncio
|
| 8 |
-
from flask import Flask
|
| 9 |
from rubpy.bot import BotClient, filters
|
| 10 |
|
| 11 |
-
#
|
| 12 |
-
|
| 13 |
-
# ====================================================================
|
| 14 |
-
app = Flask(__name__)
|
| 15 |
|
| 16 |
HF_PODCAST_URL = "https://ezmarynoori-podgen.hf.space"
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
@app.route('/')
|
| 20 |
def home():
|
| 21 |
-
return "ربات روبیکا
|
| 22 |
-
|
| 23 |
-
@app.route('/proxy/<target>/<path:subpath>', methods=['GET', 'POST', 'OPTIONS'])
|
| 24 |
-
def proxy_hub(target, subpath):
|
| 25 |
-
if request.method == 'OPTIONS':
|
| 26 |
-
return Response("", status=200)
|
| 27 |
-
|
| 28 |
-
if target == 'podcast':
|
| 29 |
-
base_url = HF_PODCAST_URL
|
| 30 |
-
elif target == 'sada':
|
| 31 |
-
base_url = HF_SADA_URL
|
| 32 |
-
else:
|
| 33 |
-
return "Invalid target", 400
|
| 34 |
-
|
| 35 |
-
url = f"{base_url}/{subpath}"
|
| 36 |
-
|
| 37 |
-
# هدرهای دور زدن فیلترینگ و کلودفلر
|
| 38 |
-
headers = {
|
| 39 |
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
| 40 |
-
'Accept': '*/*',
|
| 41 |
-
'X-App-Auth': request.headers.get('X-App-Auth', ''),
|
| 42 |
-
'X-CSRF-Token': request.headers.get('X-CSRF-Token', '')
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
if request.is_json:
|
| 46 |
-
headers['Content-Type'] = 'application/json'
|
| 47 |
-
elif request.content_type and not request.files:
|
| 48 |
-
headers['Content-Type'] = request.content_type
|
| 49 |
-
|
| 50 |
-
# حذف هدرهای خالی
|
| 51 |
-
headers = {k: v for k, v in headers.items() if v}
|
| 52 |
-
|
| 53 |
-
try:
|
| 54 |
-
if request.method == 'POST':
|
| 55 |
-
if request.files:
|
| 56 |
-
# تبدیل امن فایلهای صوتی برای آپلود بدون قطعی استریم
|
| 57 |
-
files_dict = {}
|
| 58 |
-
for k, v in request.files.items():
|
| 59 |
-
files_dict[k] = (v.filename, v.read(), v.content_type)
|
| 60 |
-
|
| 61 |
-
form_data = dict(request.form)
|
| 62 |
-
res = requests.post(url, data=form_data, files=files_dict, headers=headers, timeout=120)
|
| 63 |
-
else:
|
| 64 |
-
data = request.get_data()
|
| 65 |
-
res = requests.post(url, data=data, headers=headers, timeout=120)
|
| 66 |
-
else:
|
| 67 |
-
res = requests.get(url, params=request.args, headers=headers, timeout=120)
|
| 68 |
-
|
| 69 |
-
return Response(
|
| 70 |
-
res.content,
|
| 71 |
-
status=res.status_code,
|
| 72 |
-
content_type=res.headers.get('Content-Type', 'application/json')
|
| 73 |
-
)
|
| 74 |
-
except requests.exceptions.Timeout:
|
| 75 |
-
return Response('{"message": "ارتباط با سرور هوش مصنوعی قطع شد (تایماوت)"}', status=504, mimetype='application/json')
|
| 76 |
-
except Exception as e:
|
| 77 |
-
print(f"Proxy Error: {str(e)}")
|
| 78 |
-
return Response(f'{{"message": "ارور تونل پایتون: {str(e)}"}}', status=500, mimetype='application/json')
|
| 79 |
|
| 80 |
def run_flask():
|
| 81 |
-
|
|
|
|
|
|
|
| 82 |
|
| 83 |
|
| 84 |
-
# =======================================================
|
| 85 |
-
# 🤖
|
| 86 |
-
# =======================================================
|
| 87 |
WORKER_URLS =[
|
| 88 |
"https://hamed744-ttspro.hf.space/generate",
|
| 89 |
"https://hamed744-ttspro2.hf.space/generate",
|
|
@@ -97,28 +102,20 @@ WORKER_URLS =[
|
|
| 97 |
]
|
| 98 |
|
| 99 |
SPEAKERS = {
|
| 100 |
-
"1": ("شهاب
|
| 101 |
-
"4": ("آرمان
|
| 102 |
-
"7": ("سامان
|
| 103 |
-
"10": ("سحر
|
| 104 |
-
"13": ("نیکان (مرد)", "Schedar"), "14": ("فرناز (زن)", "Gacrux"), "15": ("سارا (زن)", "Pulcherrima"),
|
| 105 |
-
"16": ("مانی (مرد)", "Umbriel"), "17": ("آرتین (مرد)", "Algieba"), "18": ("دلنواز (زن)", "Despina"),
|
| 106 |
-
"19": ("روژان (زن)", "Erinome"), "20": ("امید (مرد)", "Algenib"), "21": ("بردیا (مرد)", "Orus"),
|
| 107 |
-
"22": ("ترانه (زن)", "Aoede"), "23": ("نیکو (زن)", "Callirrhoe"), "24": ("هستی (زن)", "Autonoe"),
|
| 108 |
-
"25": ("کامیار (مرد)", "Enceladus"), "26": ("کیانوش (مرد)", "Iapetus"), "27": ("پویا (مرد)", "Puck"),
|
| 109 |
-
"28": ("مهتاب (زن)", "Kore"), "29": ("سام (مرد)", "Fenrir"), "30": ("لیدا (زن)", "Leda")
|
| 110 |
}
|
| 111 |
|
| 112 |
user_states = {}
|
| 113 |
|
| 114 |
async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
| 115 |
try:
|
| 116 |
-
await client.send_message(chat_id, f"⏳ در حال ساخت صدا
|
| 117 |
-
|
| 118 |
payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
|
| 119 |
headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
|
| 120 |
audio_bytes = None
|
| 121 |
-
last_error = "هیچ پاسخی دریافت نشد"
|
| 122 |
|
| 123 |
workers = WORKER_URLS.copy()
|
| 124 |
random.shuffle(workers)
|
|
@@ -128,64 +125,39 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
|
| 128 |
try:
|
| 129 |
async with session.post(worker_url, json=payload, timeout=60) as response:
|
| 130 |
if response.status == 200:
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
break
|
| 135 |
-
else:
|
| 136 |
-
last_error = "سرور به جای صدا، فایل نامعتبر داد."
|
| 137 |
-
else:
|
| 138 |
-
last_error = f"ارور سرور ({response.status})"
|
| 139 |
-
except Exception as e:
|
| 140 |
-
last_error = str(e)
|
| 141 |
continue
|
| 142 |
|
| 143 |
if audio_bytes:
|
| 144 |
-
file_name = f"
|
| 145 |
-
with open(file_name, "wb") as f:
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
await client.send_voice(chat_id, file_name)
|
| 150 |
-
except Exception:
|
| 151 |
-
try:
|
| 152 |
-
await client.send_document(chat_id, file_name)
|
| 153 |
-
except Exception:
|
| 154 |
-
await client.send_message(chat_id, "✅ صدا ساخته شد اما محدودیت ارسال فایل در روبیکا وجود دارد.")
|
| 155 |
-
|
| 156 |
-
if os.path.exists(file_name):
|
| 157 |
-
os.remove(file_name)
|
| 158 |
else:
|
| 159 |
-
await client.send_message(chat_id,
|
| 160 |
|
| 161 |
except Exception as e:
|
| 162 |
-
print(f"خطای پردازش صدا: {e}")
|
| 163 |
traceback.print_exc()
|
| 164 |
|
| 165 |
bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
|
| 166 |
|
| 167 |
if bot_token:
|
| 168 |
bot = BotClient(bot_token)
|
| 169 |
-
|
| 170 |
@bot.on_update(filters.private)
|
| 171 |
async def main_handler(client, update):
|
| 172 |
try:
|
| 173 |
-
user_text = ""
|
| 174 |
-
if hasattr(update, "text") and update.text:
|
| 175 |
-
user_text = update.text
|
| 176 |
-
elif hasattr(update, "message") and hasattr(update.message, "text") and update.message.text:
|
| 177 |
-
user_text = update.message.text
|
| 178 |
-
elif hasattr(update, "new_message") and hasattr(update.new_message, "text") and update.new_message.text:
|
| 179 |
-
user_text = update.new_message.text
|
| 180 |
-
|
| 181 |
if not user_text: return
|
| 182 |
chat_id = getattr(update, "chat_id", None) or getattr(update, "author_guid", None) or getattr(update, "object_guid", None)
|
| 183 |
if not chat_id: return
|
| 184 |
-
|
| 185 |
user_text_str = str(user_text).strip()
|
| 186 |
|
| 187 |
-
if user_text_str in
|
| 188 |
-
await update.reply("سلام! 🎙️\n
|
| 189 |
return
|
| 190 |
|
| 191 |
if chat_id in user_states:
|
|
@@ -194,35 +166,13 @@ if bot_token:
|
|
| 194 |
saved_text = user_states.pop(chat_id)
|
| 195 |
asyncio.create_task(process_tts(client, chat_id, saved_text, speaker_id, speaker_name))
|
| 196 |
return
|
| 197 |
-
elif user_text_str.isdigit():
|
| 198 |
-
await update.reply("❌ شماره وارد شده نامعتبر است! لطفاً یک عدد بین ۱ تا ۳۰ بفرستید.")
|
| 199 |
-
return
|
| 200 |
-
|
| 201 |
-
if len(user_text_str) > 500:
|
| 202 |
-
await update.reply("⚠️ کاربر گرامی، لطفاً متنی کوتاهتر از ۵۰۰ کاراکتر بفرستید.")
|
| 203 |
-
return
|
| 204 |
|
| 205 |
user_states[chat_id] = user_text_str
|
| 206 |
-
|
| 207 |
-
menu_text = """📝 متن ذخیره شد! فقط **شماره** گوینده را از لیست زیر بفرستید:
|
| 208 |
-
|
| 209 |
-
1. شهاب (مرد) | 2. آوا (زن) | 3. نوید (مرد)
|
| 210 |
-
4. آرمان (مرد) | 5. مهسا (زن) | 6. دانا (مرد)
|
| 211 |
-
7. سامان (مرد) | 8. آرش (مرد) | 9. شبنم (زن)
|
| 212 |
-
10. سحر (زن) | 11. مری�� (زن) | 12. بهرام (مرد)
|
| 213 |
-
13. نیکان (مرد)| 14. فرناز (زن) | 15. سارا (زن)
|
| 214 |
-
16. مانی (مرد) | 17. آرتین (مرد) | 18. دلنواز (زن)
|
| 215 |
-
19. روژان (زن) | 20. امید (مرد) | 21. بردیا (مرد)
|
| 216 |
-
22. ترانه (زن) | 23. نیکو (زن) | 24. هستی (زن)
|
| 217 |
-
25. کامیار (مرد)| 26. کیانوش (مرد)| 27. پویا (مرد)
|
| 218 |
-
28. مهتاب (زن) | 29. سام (مرد) | 30. لیدا (زن)"""
|
| 219 |
-
await update.reply(menu_text)
|
| 220 |
|
| 221 |
except Exception as e:
|
| 222 |
traceback.print_exc()
|
| 223 |
|
| 224 |
if __name__ == "__main__":
|
| 225 |
threading.Thread(target=run_flask, daemon=True).start()
|
| 226 |
-
if bot_token:
|
| 227 |
-
print("ربات روبیکا و سرور تونل روشن شد...")
|
| 228 |
-
bot.run()
|
|
|
|
| 3 |
import random
|
| 4 |
import aiohttp
|
| 5 |
import requests
|
| 6 |
+
import json
|
| 7 |
+
import time
|
| 8 |
import traceback
|
| 9 |
import asyncio
|
| 10 |
+
from flask import Flask
|
| 11 |
from rubpy.bot import BotClient, filters
|
| 12 |
|
| 13 |
+
# 🔴🔴🔴 مسیر فایل PHP سایت خود را اینجا وارد کنید 🔴🔴🔴
|
| 14 |
+
SITE_URL = "https://aisada.ir/tts/proxy.php"
|
|
|
|
|
|
|
| 15 |
|
| 16 |
HF_PODCAST_URL = "https://ezmarynoori-podgen.hf.space"
|
| 17 |
+
|
| 18 |
+
# =======================================================
|
| 19 |
+
# 🌐 ۱. موتور مکنده (Reverse Tunnel) برای زنده کردن سایت
|
| 20 |
+
# =======================================================
|
| 21 |
+
def reverse_tunnel_worker():
|
| 22 |
+
while True:
|
| 23 |
+
try:
|
| 24 |
+
# ۱. گرفتن درخواستها از سایت ایران
|
| 25 |
+
pull_res = requests.get(f"{SITE_URL}?endpoint=hf-pull", timeout=10)
|
| 26 |
+
if pull_res.status_code == 200:
|
| 27 |
+
tasks = pull_res.json()
|
| 28 |
+
for task in tasks:
|
| 29 |
+
task_id = task.get('id')
|
| 30 |
+
endpoint = task.get('endpoint')
|
| 31 |
+
payload = task.get('payload', {})
|
| 32 |
+
|
| 33 |
+
# تنظیم لینک مقصد (مدلهای هوش مصنوعی)
|
| 34 |
+
if endpoint == 'generate':
|
| 35 |
+
target_url = f"{HF_PODCAST_URL}/api/generate"
|
| 36 |
+
elif endpoint == 'check-tts-status':
|
| 37 |
+
target_url = f"{HF_PODCAST_URL}/api/check_status"
|
| 38 |
+
elif endpoint == 'create-full-podcast':
|
| 39 |
+
target_url = f"{HF_PODCAST_URL}/api/create-full-podcast"
|
| 40 |
+
elif endpoint == 'podcast-status':
|
| 41 |
+
task_id_param = task.get('get_params', {}).get('task_id', '')
|
| 42 |
+
target_url = f"{HF_PODCAST_URL}/api/podcast-status/{task_id_param}"
|
| 43 |
+
else:
|
| 44 |
+
continue
|
| 45 |
+
|
| 46 |
+
# ۲. ارسال به مدل هوش مصنوعی (داخل هاگینگ فیس)
|
| 47 |
+
headers = {'Content-Type': 'application/json'}
|
| 48 |
+
if endpoint == 'podcast-status':
|
| 49 |
+
model_res = requests.get(target_url, timeout=90)
|
| 50 |
+
else:
|
| 51 |
+
model_res = requests.post(target_url, json=payload, headers=headers, timeout=90)
|
| 52 |
+
|
| 53 |
+
# ۳. ارسال فایل/جواب آماده شده به سایت ایران
|
| 54 |
+
push_url = f"{SITE_URL}?endpoint=hf-push"
|
| 55 |
+
if model_res.status_code == 200:
|
| 56 |
+
content_type = model_res.headers.get('Content-Type', '')
|
| 57 |
+
if 'audio' in content_type or model_res.content[:4] == b'RIFF':
|
| 58 |
+
# ارسال فایل صدا
|
| 59 |
+
files = {'file': (f"{task_id}.wav", model_res.content, 'audio/wav')}
|
| 60 |
+
requests.post(push_url, data={'id': task_id}, files=files, timeout=30)
|
| 61 |
+
else:
|
| 62 |
+
# ارسال پاسخهای JSON
|
| 63 |
+
requests.post(push_url, data={'id': task_id, 'json_data': model_res.content}, timeout=30)
|
| 64 |
+
else:
|
| 65 |
+
err = {'error': f"خطای هوش مصنوعی ({model_res.status_code})"}
|
| 66 |
+
requests.post(push_url, data={'id': task_id, 'json_data': json.dumps(err)}, timeout=30)
|
| 67 |
+
|
| 68 |
+
except Exception as e:
|
| 69 |
+
# بیصدا بودن خطا برای جلوگیری از توقف حلقه
|
| 70 |
+
pass
|
| 71 |
+
|
| 72 |
+
time.sleep(1) # بررسی سایت هر 1 ثانیه
|
| 73 |
+
|
| 74 |
+
# =======================================================
|
| 75 |
+
# 🌐 ۲. سرور زنده نگهدارنده (Flask)
|
| 76 |
+
# =======================================================
|
| 77 |
+
app = Flask(__name__)
|
| 78 |
|
| 79 |
@app.route('/')
|
| 80 |
def home():
|
| 81 |
+
return "✅ سرور نجات سایت و ربات روبیکا با موفقیت فعال است!"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
def run_flask():
|
| 84 |
+
# شروع بکار موتور مکنده در پسزمینه
|
| 85 |
+
threading.Thread(target=reverse_tunnel_worker, daemon=True).start()
|
| 86 |
+
app.run(host="0.0.0.0", port=7860)
|
| 87 |
|
| 88 |
|
| 89 |
+
# =======================================================
|
| 90 |
+
# 🤖 ۳. ربات روبیکا
|
| 91 |
+
# =======================================================
|
| 92 |
WORKER_URLS =[
|
| 93 |
"https://hamed744-ttspro.hf.space/generate",
|
| 94 |
"https://hamed744-ttspro2.hf.space/generate",
|
|
|
|
| 102 |
]
|
| 103 |
|
| 104 |
SPEAKERS = {
|
| 105 |
+
"1": ("شهاب", "Charon"), "2": ("آوا", "Zephyr"), "3": ("نوید", "Achird"),
|
| 106 |
+
"4": ("آرمان", "Zubenelgenubi"), "5": ("مهسا", "Vindemiatrix"), "6": ("دانا", "Rasalgethi"),
|
| 107 |
+
"7": ("سامان", "Sadachbia"), "8": ("آرش", "Sadaltager"), "9": ("شبنم", "Sulafat"),
|
| 108 |
+
"10": ("سحر", "Laomedeia")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
}
|
| 110 |
|
| 111 |
user_states = {}
|
| 112 |
|
| 113 |
async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
| 114 |
try:
|
| 115 |
+
await client.send_message(chat_id, f"⏳ در حال ساخت صدا...\n(گوینده: {speaker_name})")
|
|
|
|
| 116 |
payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
|
| 117 |
headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
|
| 118 |
audio_bytes = None
|
|
|
|
| 119 |
|
| 120 |
workers = WORKER_URLS.copy()
|
| 121 |
random.shuffle(workers)
|
|
|
|
| 125 |
try:
|
| 126 |
async with session.post(worker_url, json=payload, timeout=60) as response:
|
| 127 |
if response.status == 200:
|
| 128 |
+
audio_bytes = await response.read()
|
| 129 |
+
break
|
| 130 |
+
except Exception:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
continue
|
| 132 |
|
| 133 |
if audio_bytes:
|
| 134 |
+
file_name = f"voice_{random.randint(1000, 9999)}.wav"
|
| 135 |
+
with open(file_name, "wb") as f: f.write(audio_bytes)
|
| 136 |
+
try: await client.send_voice(chat_id, file_name)
|
| 137 |
+
except: await client.send_document(chat_id, file_name)
|
| 138 |
+
if os.path.exists(file_name): os.remove(file_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
else:
|
| 140 |
+
await client.send_message(chat_id, "❌ خطای سرور. لطفاً مجدد تلاش کنید.")
|
| 141 |
|
| 142 |
except Exception as e:
|
|
|
|
| 143 |
traceback.print_exc()
|
| 144 |
|
| 145 |
bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
|
| 146 |
|
| 147 |
if bot_token:
|
| 148 |
bot = BotClient(bot_token)
|
|
|
|
| 149 |
@bot.on_update(filters.private)
|
| 150 |
async def main_handler(client, update):
|
| 151 |
try:
|
| 152 |
+
user_text = getattr(update, "text", "") or getattr(getattr(update, "message", None), "text", "") or getattr(getattr(update, "new_message", None), "text", "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
if not user_text: return
|
| 154 |
chat_id = getattr(update, "chat_id", None) or getattr(update, "author_guid", None) or getattr(update, "object_guid", None)
|
| 155 |
if not chat_id: return
|
| 156 |
+
|
| 157 |
user_text_str = str(user_text).strip()
|
| 158 |
|
| 159 |
+
if user_text_str in["/start", "سلام"]:
|
| 160 |
+
await update.reply("سلام! 🎙️\nهر متنی دوست داری بفرست تا با صداهای مختلف برات بخونمش.")
|
| 161 |
return
|
| 162 |
|
| 163 |
if chat_id in user_states:
|
|
|
|
| 166 |
saved_text = user_states.pop(chat_id)
|
| 167 |
asyncio.create_task(process_tts(client, chat_id, saved_text, speaker_id, speaker_name))
|
| 168 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
user_states[chat_id] = user_text_str
|
| 171 |
+
await update.reply("📝 متن شما ذخیره شد!\nیک شماره بین 1 تا 10 برای انتخاب گوینده بفرستید.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
except Exception as e:
|
| 174 |
traceback.print_exc()
|
| 175 |
|
| 176 |
if __name__ == "__main__":
|
| 177 |
threading.Thread(target=run_flask, daemon=True).start()
|
| 178 |
+
if bot_token: bot.run()
|
|
|
|
|
|