Opera8 commited on
Commit
e3e8ac3
·
verified ·
1 Parent(s): 2d3350b

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +286 -168
main.py CHANGED
@@ -311,16 +311,99 @@ def to_english_digits(text):
311
  return str(text).translate(translation_table)
312
 
313
  # ==============================================================================
314
- # 🟢 پارت 6: تنظیمات وب‌سرور (Flask) و توابع کمکی فایل‌ها
315
  # ==============================================================================
316
- # --- تنظیمات وب سرور ---
 
 
 
 
317
  app = Flask(__name__)
318
 
319
- @app.route('/')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  def home():
321
- return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دعوت دوستان + سیستم تغییر صدا) روشن است! 🚀"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
  def run_flask():
 
 
 
 
324
  app.run(host="0.0.0.0", port=7860, threaded=True)
325
 
326
  # --- توابع کمکی ---
@@ -337,12 +420,17 @@ def sync_read_file(file_name):
337
  return f.read()
338
 
339
  def sync_combine_audio(current_audio, new_bytes):
 
 
340
  audio_segment = AudioSegment.from_file(io.BytesIO(new_bytes))
341
  return current_audio + audio_segment
342
 
343
  def sync_export_audio(audio_obj, file_name):
344
  audio_obj.export(file_name, format="mp3")
345
 
 
 
 
346
  # ==============================================================================
347
  # 🟢 پارت 7: کیبوردها (دکمه���های شیشه‌ای / منوها)
348
  # ==============================================================================
@@ -614,22 +702,19 @@ HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
614
  # ==============================================================================
615
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
616
  abs_path = os.path.abspath(file_name)
617
- error_logs = []
618
 
619
- api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
620
 
621
- # روبیکا فرمت‌های خاصی را قبول می‌کند.
622
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
623
  api_file_type = "Music"
624
  if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
625
  api_file_type = "Music"
626
 
627
- # --- فاز اول (فوق سریع): استفاده از متدهای اختصاصی rubpy ---
628
- for attempt in range(10):
629
  try:
630
  sent_success = False
631
-
632
- # تلاش برای ارسال عکس
633
  if api_file_type == "Image" and hasattr(client, "send_photo"):
634
  try:
635
  await client.send_photo(chat_id, photo=abs_path, caption=caption)
@@ -638,7 +723,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
638
  await client.send_photo(chat_id, abs_path, caption=caption)
639
  sent_success = True
640
 
641
- # تلاش برای ارسال ویس
642
  elif api_file_type == "Voice" and hasattr(client, "send_voice"):
643
  try:
644
  await client.send_voice(chat_id, abs_path, caption=caption)
@@ -647,7 +731,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
647
  await client.send_voice(chat_id, file=abs_path, caption=caption)
648
  sent_success = True
649
 
650
- # تلاش برای ارسال موزیک
651
  elif api_file_type == "Music" and hasattr(client, "send_music"):
652
  try:
653
  await client.send_music(chat_id, abs_path, caption=caption)
@@ -656,8 +739,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
656
  await client.send_music(chat_id, music=abs_path, caption=caption)
657
  sent_success = True
658
 
659
- # *** سیستم ضد بمب اتم فاز 1 ***
660
- # اگر هیچکدام از متدهای بالا وجود نداشت یا به هر دلیلی ارسال نشد، حتما به عنوان فایل (سند) بفرست تا معطل نشود
661
  if not sent_success:
662
  if hasattr(client, "send_document"):
663
  try:
@@ -679,28 +760,34 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
679
  return True
680
 
681
  except Exception as e:
682
- err_msg = str(e)[:150]
683
- error_logs.append(f"Rubpy Send Error: {err_msg}")
684
-
685
- if "502" in err_msg or "timeout" in err_msg.lower() or "time" in err_msg.lower():
686
- await asyncio.sleep(4)
687
  else:
688
- await asyncio.sleep(2)
689
 
690
- # --- فاز دوم (سنگر آخر): آپلود دستی (Raw HTTP) در صورت مسدودی کامل روب‌پای ---
691
- for attempt in range(15):
692
  try:
693
  url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
694
  url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
695
 
696
  async with aiohttp.ClientSession() as session:
697
- async with session.post(url_request, json={"type": api_file_type}, timeout=30) as resp:
698
  if resp.status != 200:
699
- error_logs.append(f"Request HTTP {resp.status}")
700
- await asyncio.sleep(2)
701
  continue
702
 
703
  req_data = await resp.json()
 
 
 
 
 
 
 
704
  if req_data.get("status") == "OK":
705
  upload_url = req_data.get("data", {}).get("upload_url")
706
  if upload_url:
@@ -709,28 +796,24 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
709
  form.add_field('file', f, filename=os.path.basename(abs_path))
710
  async with session.post(upload_url, data=form, timeout=300) as up_resp:
711
  if up_resp.status != 200:
712
- error_logs.append(f"Upload HTTP {up_resp.status}")
713
- if up_resp.status in[502, 503, 500]:
714
- await asyncio.sleep(3)
715
- else:
716
- await asyncio.sleep(1.5)
717
  continue
718
 
719
  try:
720
  up_data = await up_resp.json()
721
- except Exception as json_err:
722
- error_logs.append(f"JSON Decode Error: {json_err}")
723
- await asyncio.sleep(2)
724
  continue
725
 
 
 
 
 
726
  final_file_id = None
727
 
728
- # *** سیستم ضد بمب اتم فاز 2 ***
729
- # دور زدن ارور روبیکا: اگر روبیکا به فرمت فایل گیر داد، سریعاً نوع را به File تغییر بده تا بدون بررسی فرمت آپلود کند!
730
  if up_data.get("status") == "INVALID_INPUT" and "format" in str(up_data).lower():
731
  api_file_type = "File"
732
- error_logs.append(f"Format Blocked! Downgrading type to File.")
733
- await asyncio.sleep(1)
734
  continue
735
 
736
  if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
@@ -747,34 +830,26 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
747
  "chat_keypad_type": "New",
748
  "chat_keypad": MAIN_KEYPAD_DICT
749
  }
750
- async with session.post(url_send, json=send_payload, timeout=30) as send_resp:
751
- if send_resp.status != 200:
752
- error_logs.append(f"Send HTTP {send_resp.status}")
753
- await asyncio.sleep(2)
754
- continue
755
-
756
  s_data = await send_resp.json()
757
- if s_data.get("status") == "OK": return True
758
- else: error_logs.append(f"SendFile API Error: {s_data}")
 
 
 
759
  else:
760
  if up_data.get("status") == "INVALID_INPUT" and api_file_type in ["Voice", "Music"]:
761
- api_file_type = "File" # دور زدن گیر دادن روبیکا
762
- error_logs.append(f"Upload API Error: {up_data}")
763
- else: error_logs.append(f"Missing upload_url in Response: {req_data}")
764
- else: error_logs.append(f"Request API Error: {req_data}")
765
  except Exception as e:
766
- error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
767
- await asyncio.sleep(2.5)
768
 
769
  return "\n".join(error_logs[-6:])
770
 
771
  # ==============================================================================
772
  # 🟢 پارت 12: توابع تغییر صدا و لیست گویندگان
773
  # ==============================================================================
774
- # ==================================================================
775
- # لیست‌های اولیه ربات
776
- # ==================================================================
777
- WORKER_URLS =["https://opera8-ttspro.hf.space/generate"]
778
 
779
  SPEAKERS = {
780
  "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
@@ -791,80 +866,100 @@ SPEAKERS = {
791
 
792
  user_states = {}
793
 
794
- # ==================================================================
795
- # توابع تغییر صدا و کلون کردن
796
- # ==================================================================
797
  async def process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, job_type_name, credit_type):
798
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
799
  creds = get_user_credits(str_chat_id)
800
 
801
- proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {job_type_name})", False)
802
 
803
- async with aiohttp.ClientSession() as session:
804
- form = aiohttp.FormData()
805
- form.add_field('source_audio', src_bytes, filename='src.wav', content_type='audio/wav')
806
- form.add_field('ref_audio', ref_bytes, filename='ref.wav', content_type='audio/wav')
807
-
808
- try:
809
- async with session.post(f"{VC_BASE_URL}/upload", data=form, timeout=43200) as resp:
810
- if resp.status != 200:
811
- return await send_with_keyboard(client, chat_id, f"❌ خطا در ارسال فایل‌ها (کد {resp.status})", True)
812
- data = await resp.json()
813
- job_id = data.get("job_id")
814
- total_chunks = data.get("total_chunks", 1)
815
- chunks = data.get("chunks",[])
816
- except Exception as e:
817
- return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور:\n{str(e)[:100]}", True)
 
 
 
 
 
 
 
 
 
 
 
818
 
819
- await send_with_keyboard(client, chat_id, "✅ فایل‌ها ارسال شد. در حال پردازش و تغییر صدا...\n(لطفا چند دقیقه صبور باشید)", False)
820
-
821
- final_filename = None
822
- for _ in range(10000):
823
- await asyncio.sleep(4)
 
 
 
 
824
  payload_check = {"job_id": job_id, "total_chunks": total_chunks, "chunks": chunks}
825
  try:
826
- async with session.post(f"{VC_BASE_URL}/check_status", json=payload_check, timeout=20) as c_resp:
827
  if c_resp.status == 200:
828
  c_data = await c_resp.json()
829
  if c_data.get("status") == "completed":
830
  final_filename = c_data.get("filename")
831
  break
832
  elif c_data.get("status") in ["failed", "error"]:
833
- return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش صدا.", True)
834
  except Exception:
835
  pass
836
 
837
  if not final_filename:
838
- return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True)
839
 
840
  download_url = f"{VC_BASE_URL}/download/{final_filename}"
841
  await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
842
- try:
843
- async with session.get(download_url, timeout=43200) as d_resp:
844
- if d_resp.status == 200:
845
- result_bytes = await d_resp.read()
846
- else:
847
- return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
848
- except Exception:
849
- return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی.", True)
 
 
 
 
 
 
 
850
 
851
  file_name_mp3 = f"vc_standard_{uuid.uuid4().hex[:6]}.mp3"
852
  await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
853
 
854
  upload_result = False
855
- for up_att in range(3):
 
856
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ {job_type_name} شما آماده است!")
857
  if res is True:
858
  upload_result = True
859
  break
860
- await asyncio.sleep(4)
861
 
862
  if upload_result is True:
863
  if not creds.get("is_premium"):
864
  user_credits_db[str_chat_id][credit_type] -= 1
865
  save_db(user_credits_db)
866
  else:
867
- await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال در روبیکا فراهم نشد.", True)
868
 
869
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
870
 
@@ -872,37 +967,48 @@ async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, mo
872
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
873
  creds = get_user_credits(str_chat_id)
874
 
875
- proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {model_name})", False)
876
 
877
- async with aiohttp.ClientSession() as session:
878
- form = aiohttp.FormData()
879
- form.add_field('audio_file', src_bytes, filename='input.wav', content_type='audio/wav')
880
- form.add_field('model_url', model_url)
881
- form.add_field('pitch', str(pitch))
882
- form.add_field('algo', 'rmvpe+')
883
- form.add_field('index_inf', '0.75')
884
- form.add_field('res_filter', '3')
885
- form.add_field('env_ratio', '0.25')
886
- form.add_field('protect', '0.33')
887
- form.add_field('denoise', 'false')
888
- form.add_field('reverb', 'false')
889
-
890
- try:
891
- async with session.post(f"{LEGACY_BASE_URL}/upload", data=form, timeout=43200) as resp:
892
- if resp.status != 200:
893
- return await send_with_keyboard(client, chat_id, f"❌ خطا در ارسال فایل‌ها (کد {resp.status})", True)
894
- data = await resp.json()
895
- job_id = data.get("job_id")
896
- except Exception as e:
897
- return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور:\n{str(e)[:100]}", True)
 
 
 
 
 
 
 
898
 
899
- await send_with_keyboard(client, chat_id, "✅ فایل ارسال شد. در حال پردازش و تغییر صدای شما...\n(لطفا چند دقیقه صبور باشید)", False)
900
-
901
- final_filename = None
902
- for _ in range(10000):
 
 
 
 
903
  await asyncio.sleep(5)
904
  try:
905
- async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=20) as c_resp:
906
  if c_resp.status == 200:
907
  c_data = await c_resp.json()
908
  if c_data.get("status") == "completed":
@@ -918,32 +1024,39 @@ async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, mo
918
 
919
  download_url = f"{LEGACY_BASE_URL}/download/{final_filename}"
920
  await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
921
- try:
922
- async with session.get(download_url, timeout=43200) as d_resp:
923
- if d_resp.status == 200:
924
- result_bytes = await d_resp.read()
925
- else:
926
- return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
927
- except Exception:
928
- return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی.", True)
 
 
 
 
 
 
 
929
 
930
  file_name_mp3 = f"vc_legacy_{uuid.uuid4().hex[:6]}.mp3"
931
  await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
932
 
933
  upload_result = False
934
- for up_att in range(3):
935
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ صدای خروجی با مدل {model_name} آماده است!")
936
  if res is True:
937
  upload_result = True
938
  break
939
- await asyncio.sleep(4)
940
 
941
  if upload_result is True:
942
  if not creds.get("is_premium"):
943
  user_credits_db[str_chat_id]["voice_conv"] -= 1
944
  save_db(user_credits_db)
945
  else:
946
- await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال در روبیکا فراهم نشد.", True)
947
 
948
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
949
 
@@ -1133,7 +1246,7 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1133
  async with aiohttp.ClientSession() as session:
1134
  for key in keys_to_try_gemini:
1135
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1136
- payload = {"contents": [{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
1137
  try:
1138
  async with session.post(url, json=payload, timeout=20) as response:
1139
  if response.status == 200:
@@ -1186,9 +1299,9 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1186
  proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
1187
 
1188
  generated_image = None
1189
- last_error_log = "هیچ اتصالی برقرار نشد."
1190
 
1191
- for attempt in range(5):
 
1192
  keys_to_try = HF_TOKENS.copy()
1193
  random.shuffle(keys_to_try)
1194
  for token in keys_to_try:
@@ -1202,10 +1315,12 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1202
  )
1203
  break
1204
  except Exception as e:
1205
- last_error_log = str(e)
 
 
1206
  continue
1207
  if generated_image: break
1208
- await asyncio.sleep(2)
1209
 
1210
  try:
1211
  if proc_msg:
@@ -1215,7 +1330,7 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1215
  except Exception: pass
1216
 
1217
  if not generated_image:
1218
- return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
1219
 
1220
  try:
1221
  file_name = f"image_{uuid.uuid4().hex}.jpg"
@@ -1224,26 +1339,25 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1224
  caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}"
1225
 
1226
  upload_result = False
1227
- error_log_img = ""
1228
- for up_att in range(3):
1229
  res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
1230
  if res is True:
1231
  upload_result = True
1232
  break
1233
  else:
1234
- error_log_img = res
1235
- await asyncio.sleep(4)
1236
 
1237
  if upload_result is True:
1238
  if not creds.get("is_premium"):
1239
  user_credits_db[str_chat_id]["image"] -= 1
1240
  save_db(user_credits_db)
1241
  else:
1242
- await send_with_keyboard(client, chat_id, f"❌ عکس ساخته شد اما آپلود در روبیکا با خطا مواجه شد:\n`{str(error_log_img)[:800]}`", True)
1243
 
1244
  if os.path.exists(file_name): os.remove(file_name)
1245
  except Exception as e:
1246
- await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره و ارسال عکس:\n{str(e)[:150]}", True)
1247
 
1248
  # ==============================================================================
1249
  # 🟢 پارت 15: توابع ترجمه و ویرایش عکس با هوش مصنوعی (Flux.2)
@@ -1370,9 +1484,9 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1370
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
1371
 
1372
  audio_bytes = None
1373
- last_error = "پاسخی دریافت نشد"
1374
 
1375
- for attempt in range(10):
 
1376
  workers = WORKER_URLS.copy()
1377
  random.shuffle(workers)
1378
  async with aiohttp.ClientSession(headers=headers, timeout=aiohttp.ClientTimeout(total=600)) as session:
@@ -1384,13 +1498,12 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1384
  if 'audio' in content_type or response.content_length > 1000:
1385
  audio_bytes = await response.read()
1386
  break
1387
- else: last_error = "فایل نامعتبر"
1388
- else: last_error = f"ارور ({response.status})"
1389
- except Exception as e:
1390
- last_error = f"خطا: {str(e)}"
1391
  continue
1392
  if audio_bytes: break
1393
- await asyncio.sleep(2)
1394
 
1395
  try:
1396
  if proc_msg:
@@ -1405,26 +1518,25 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1405
  await asyncio.sleep(1)
1406
 
1407
  upload_result_file = False
1408
- error_log_tts = ""
1409
- for up_att in range(3):
1410
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
1411
  if res is True:
1412
  upload_result_file = True
1413
  break
1414
  else:
1415
- error_log_tts = res
1416
- await asyncio.sleep(4)
1417
 
1418
  if upload_result_file is True:
1419
  if not creds.get("is_premium"):
1420
  user_credits_db[str_chat_id]["tts"] -= 1
1421
  save_db(user_credits_db)
1422
  else:
1423
- await send_with_keyboard(client, chat_id, f"❌ فایل صدا ساخته شد اما سرور روبیکا اجازه آپلود نداد:\n`{str(error_log_tts)[:800]}`", True)
1424
 
1425
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1426
  else:
1427
- await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
1428
  except Exception: traceback.print_exc()
1429
 
1430
  # ==============================================================================
@@ -1880,7 +1992,7 @@ if not bot_token:
1880
  else:
1881
  bot = BotClient(bot_token)
1882
 
1883
- @bot.on_update(filters.private)
1884
  async def main_handler(client, update):
1885
  global BOT_GUID
1886
 
@@ -2645,16 +2757,22 @@ else:
2645
  except Exception: traceback.print_exc()
2646
 
2647
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
2648
  threading.Thread(target=run_flask, daemon=True).start()
2649
 
2650
  if bot_token:
2651
- loop = asyncio.get_event_loop()
2652
-
2653
- # 🟢 تونل‌های پرسرعت: ارتقا از 32 کارگر به 256 کارگر برای پاسخگویی همزمان به هزاران نفر
2654
- loop.set_default_executor(concurrent.futures.ThreadPoolExecutor(max_workers=256))
2655
-
2656
- # 🟢 روشن کردن سیستم پاکسازی هوشمند رم در پس‌زمینه
2657
- loop.create_task(ram_garbage_collector())
2658
-
2659
- print("🚀 ربات آلفا پرو (نسخه صنعتی + دیتابیس هوشمند + پاکسازی رم + 256 تونل همزمان) روشن شد...")
2660
- bot.run()
 
311
  return str(text).translate(translation_table)
312
 
313
  # ==============================================================================
314
+ # 🟢 پارت 6: تنظیمات وب‌سرور (Flask)، دریافت وب‌هوک و توابع کمکی فایل‌ها
315
  # ==============================================================================
316
+ import requests
317
+ import asyncio
318
+ from flask import Flask, request, jsonify
319
+
320
+ # --- تنظیمات وب سرور و وب‌هوک ---
321
  app = Flask(__name__)
322
 
323
+ # آدرس وب‌هوک (اگر از Cloudflare Worker استفاده کردید، آدرس آن را اینجا بگذارید)
324
+ WEBHOOK_URL = "https://opera8-rubikabot.hf.space/"
325
+
326
+ def set_webhook_on_rubika():
327
+ bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
328
+ if not bot_token:
329
+ print("❌ توکن روبیکا یافت نشد!")
330
+ return
331
+
332
+ url = f"https://botapi.rubika.ir/v3/{bot_token}/updateBotEndpoints"
333
+
334
+ payload_update = {"url": WEBHOOK_URL, "type": "ReceiveUpdate"}
335
+ payload_inline = {"url": WEBHOOK_URL, "type": "ReceiveInlineMessage"}
336
+
337
+ try:
338
+ r1 = requests.post(url, json=payload_update, timeout=15)
339
+ print("🟢 Webhook Setup (ReceiveUpdate):", r1.json())
340
+
341
+ r2 = requests.post(url, json=payload_inline, timeout=15)
342
+ print("🟢 Webhook Setup (InlineMessage):", r2.json())
343
+ except Exception as e:
344
+ print("❌ Webhook Setup Failed:", e)
345
+
346
+ class UpdateWrapper:
347
+ def __init__(self, d):
348
+ self._d = d
349
+ for k, v in d.items():
350
+ if isinstance(v, dict):
351
+ setattr(self, k, UpdateWrapper(v))
352
+ elif isinstance(v, list):
353
+ setattr(self, k, [UpdateWrapper(i) if isinstance(i, dict) else i for i in v])
354
+ else:
355
+ setattr(self, k, v)
356
+
357
+ # 🟢 جادوی تطبیق متغیرهای وب‌هوک با استانداردهای ربات شما (رفع باگ خوانده نشدن پیام‌ها)
358
+ if hasattr(self, 'new_message'):
359
+ self.message = self.new_message
360
+
361
+ if hasattr(self, 'message') and isinstance(self.message, UpdateWrapper):
362
+ if hasattr(self.message, 'sender_id') and not hasattr(self.message, 'author_object_guid'):
363
+ self.message.author_object_guid = self.message.sender_id
364
+
365
+ if hasattr(self, 'chat_id') and not hasattr(self, 'object_guid'):
366
+ self.object_guid = self.chat_id
367
+ self.author_guid = self.chat_id
368
+
369
+ def to_dict(self):
370
+ return self._d
371
+
372
+ def get(self, key, default=None):
373
+ return getattr(self, key, default)
374
+
375
+ @app.route('/', methods=['GET', 'POST'])
376
  def home():
377
+ if request.method == 'GET':
378
+ return "ربات یکپارچه آلفا (نسخه پرو + وب‌هوک روبیکا) روشن است! 🚀"
379
+
380
+ if request.method == 'POST':
381
+ try:
382
+ data = request.json
383
+ if data:
384
+ inner_data = data
385
+ if "update" in data:
386
+ inner_data = data["update"]
387
+ elif "inline_message" in data:
388
+ inner_data = data["inline_message"]
389
+
390
+ wrapped_update = UpdateWrapper(inner_data)
391
+
392
+ # تسک به سرعت به حلقه اصلی پاس داده می‌شود تا سرور منتظر نماند
393
+ if 'loop' in globals() and 'main_handler' in globals():
394
+ asyncio.run_coroutine_threadsafe(main_handler(bot, wrapped_update), loop)
395
+
396
+ except Exception as e:
397
+ print("❌ Error in webhook processing:", e)
398
+
399
+ # همیشه و در کسری از ثانیه 200 OK برمی‌گردانیم تا روبیکا ارتباط را قطع نکند
400
+ return jsonify({"status": "ok"})
401
 
402
  def run_flask():
403
+ set_webhook_on_rubika()
404
+ import logging
405
+ log = logging.getLogger('werkzeug')
406
+ log.setLevel(logging.ERROR)
407
  app.run(host="0.0.0.0", port=7860, threaded=True)
408
 
409
  # --- توابع کمکی ---
 
420
  return f.read()
421
 
422
  def sync_combine_audio(current_audio, new_bytes):
423
+ from pydub import AudioSegment
424
+ import io
425
  audio_segment = AudioSegment.from_file(io.BytesIO(new_bytes))
426
  return current_audio + audio_segment
427
 
428
  def sync_export_audio(audio_obj, file_name):
429
  audio_obj.export(file_name, format="mp3")
430
 
431
+
432
+
433
+
434
  # ==============================================================================
435
  # 🟢 پارت 7: کیبوردها (دکمه���های شیشه‌ای / منوها)
436
  # ==============================================================================
 
702
  # ==============================================================================
703
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
704
  abs_path = os.path.abspath(file_name)
705
+ error_logs =[]
706
 
707
+ api_file_type = "Image" if file_type in ["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
708
 
 
709
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
710
  api_file_type = "Music"
711
  if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
712
  api_file_type = "Music"
713
 
714
+ # --- فاز اول (تلاش با متدهای روب‌پای تا 15 بار) ---
715
+ for attempt in range(15):
716
  try:
717
  sent_success = False
 
 
718
  if api_file_type == "Image" and hasattr(client, "send_photo"):
719
  try:
720
  await client.send_photo(chat_id, photo=abs_path, caption=caption)
 
723
  await client.send_photo(chat_id, abs_path, caption=caption)
724
  sent_success = True
725
 
 
726
  elif api_file_type == "Voice" and hasattr(client, "send_voice"):
727
  try:
728
  await client.send_voice(chat_id, abs_path, caption=caption)
 
731
  await client.send_voice(chat_id, file=abs_path, caption=caption)
732
  sent_success = True
733
 
 
734
  elif api_file_type == "Music" and hasattr(client, "send_music"):
735
  try:
736
  await client.send_music(chat_id, abs_path, caption=caption)
 
739
  await client.send_music(chat_id, music=abs_path, caption=caption)
740
  sent_success = True
741
 
 
 
742
  if not sent_success:
743
  if hasattr(client, "send_document"):
744
  try:
 
760
  return True
761
 
762
  except Exception as e:
763
+ err_msg = str(e)
764
+ error_logs.append(f"Rubpy Error: {err_msg[:50]}")
765
+ # سیستم ضد اسپم روبیکا: اگر ارور محدودیت درخواست داد، ۱۵ ثانیه صبر کن!
766
+ if "TOO_REQUESTS" in err_msg or "429" in err_msg or "502" in err_msg or "timeout" in err_msg.lower():
767
+ await asyncio.sleep(15)
768
  else:
769
+ await asyncio.sleep(4)
770
 
771
+ # --- فاز دوم (سنگر آخر: آپلود دستی تا 30 بار پافشاری شدید) ---
772
+ for attempt in range(30):
773
  try:
774
  url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
775
  url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
776
 
777
  async with aiohttp.ClientSession() as session:
778
+ async with session.post(url_request, json={"type": api_file_type}, timeout=60) as resp:
779
  if resp.status != 200:
780
+ await asyncio.sleep(5)
 
781
  continue
782
 
783
  req_data = await resp.json()
784
+
785
+ # 🛑 هندل کردن دقیق ارور رباتیک TOO_REQUESTS
786
+ if req_data.get("status") == "TOO_REQUESTS":
787
+ error_logs.append("Hit TOO_REQUESTS on requestSendFile. Sleeping 15s...")
788
+ await asyncio.sleep(15)
789
+ continue
790
+
791
  if req_data.get("status") == "OK":
792
  upload_url = req_data.get("data", {}).get("upload_url")
793
  if upload_url:
 
796
  form.add_field('file', f, filename=os.path.basename(abs_path))
797
  async with session.post(upload_url, data=form, timeout=300) as up_resp:
798
  if up_resp.status != 200:
799
+ await asyncio.sleep(5)
 
 
 
 
800
  continue
801
 
802
  try:
803
  up_data = await up_resp.json()
804
+ except Exception:
805
+ await asyncio.sleep(3)
 
806
  continue
807
 
808
+ if up_data.get("status") == "TOO_REQUESTS":
809
+ await asyncio.sleep(15)
810
+ continue
811
+
812
  final_file_id = None
813
 
 
 
814
  if up_data.get("status") == "INVALID_INPUT" and "format" in str(up_data).lower():
815
  api_file_type = "File"
816
+ await asyncio.sleep(2)
 
817
  continue
818
 
819
  if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
 
830
  "chat_keypad_type": "New",
831
  "chat_keypad": MAIN_KEYPAD_DICT
832
  }
833
+ async with session.post(url_send, json=send_payload, timeout=60) as send_resp:
 
 
 
 
 
834
  s_data = await send_resp.json()
835
+ if s_data.get("status") == "TOO_REQUESTS":
836
+ await asyncio.sleep(15)
837
+ continue
838
+ if s_data.get("status") == "OK":
839
+ return True
840
  else:
841
  if up_data.get("status") == "INVALID_INPUT" and api_file_type in ["Voice", "Music"]:
842
+ api_file_type = "File"
 
 
 
843
  except Exception as e:
844
+ error_logs.append(f"Raw HTTP Error: {str(e)[:50]}")
845
+ await asyncio.sleep(5)
846
 
847
  return "\n".join(error_logs[-6:])
848
 
849
  # ==============================================================================
850
  # 🟢 پارت 12: توابع تغییر صدا و لیست گویندگان
851
  # ==============================================================================
852
+ WORKER_URLS = ["https://opera8-ttspro.hf.space/generate"]
 
 
 
853
 
854
  SPEAKERS = {
855
  "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
 
866
 
867
  user_states = {}
868
 
 
 
 
869
  async def process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, job_type_name, credit_type):
870
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
871
  creds = get_user_credits(str_chat_id)
872
 
873
+ await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {job_type_name})", False)
874
 
875
+ job_id = None
876
+ total_chunks = 1
877
+ chunks =[]
878
+
879
+ # 🛑 پافشاری ۳۰ بار برای آپلود به سرور تغییر صدا (ضد ارور 429)
880
+ for attempt in range(30):
881
+ async with aiohttp.ClientSession() as session:
882
+ # فرم باید در هر تلاش از نو ساخته شود
883
+ form = aiohttp.FormData()
884
+ form.add_field('source_audio', src_bytes, filename='src.wav', content_type='audio/wav')
885
+ form.add_field('ref_audio', ref_bytes, filename='ref.wav', content_type='audio/wav')
886
+ try:
887
+ async with session.post(f"{VC_BASE_URL}/upload", data=form, timeout=120) as resp:
888
+ if resp.status == 429: # شلوغی سرور اسپیس
889
+ await asyncio.sleep(15)
890
+ continue
891
+ if resp.status == 200:
892
+ data = await resp.json()
893
+ job_id = data.get("job_id")
894
+ total_chunks = data.get("total_chunks", 1)
895
+ chunks = data.get("chunks",[])
896
+ break
897
+ else:
898
+ await asyncio.sleep(5)
899
+ except Exception:
900
+ await asyncio.sleep(5)
901
 
902
+ if not job_id:
903
+ return await send_with_keyboard(client, chat_id, "❌ پردازش ناموفق بود. ترافیک ربات بسیار بالاست، لطفا چند دقیقه دیگر مجدداً تلاش کنید.", True)
904
+
905
+ await send_with_keyboard(client, chat_id, "✅ فایل‌ها ارسال شد. در حال پردازش و تغییر صدا...\n(لطفا چند دقیقه صبور باشید)", False)
906
+
907
+ final_filename = None
908
+ async with aiohttp.ClientSession() as session:
909
+ for _ in range(1000): # حل��ه بی‌نهایت چک کردن استتوس
910
+ await asyncio.sleep(5)
911
  payload_check = {"job_id": job_id, "total_chunks": total_chunks, "chunks": chunks}
912
  try:
913
+ async with session.post(f"{VC_BASE_URL}/check_status", json=payload_check, timeout=30) as c_resp:
914
  if c_resp.status == 200:
915
  c_data = await c_resp.json()
916
  if c_data.get("status") == "completed":
917
  final_filename = c_data.get("filename")
918
  break
919
  elif c_data.get("status") in ["failed", "error"]:
920
+ return await send_with_keyboard(client, chat_id, "❌ خطای داخلی سرور در حین ساخت صدا رخ داد.", True)
921
  except Exception:
922
  pass
923
 
924
  if not final_filename:
925
+ return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید.", True)
926
 
927
  download_url = f"{VC_BASE_URL}/download/{final_filename}"
928
  await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
929
+
930
+ result_bytes = None
931
+ for attempt in range(30):
932
+ try:
933
+ async with session.get(download_url, timeout=120) as d_resp:
934
+ if d_resp.status == 200:
935
+ result_bytes = await d_resp.read()
936
+ break
937
+ elif d_resp.status == 429:
938
+ await asyncio.sleep(10)
939
+ except Exception:
940
+ await asyncio.sleep(5)
941
+
942
+ if not result_bytes:
943
+ return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
944
 
945
  file_name_mp3 = f"vc_standard_{uuid.uuid4().hex[:6]}.mp3"
946
  await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
947
 
948
  upload_result = False
949
+ # پافشاری بسیار بالا برای آپلود نهایی به روبیکا
950
+ for up_att in range(15):
951
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ {job_type_name} شما آماده است!")
952
  if res is True:
953
  upload_result = True
954
  break
955
+ await asyncio.sleep(5)
956
 
957
  if upload_result is True:
958
  if not creds.get("is_premium"):
959
  user_credits_db[str_chat_id][credit_type] -= 1
960
  save_db(user_credits_db)
961
  else:
962
+ await send_with_keyboard(client, chat_id, "❌ فایل با موفقیت پردازش شد اما ارسال آن به دلیل شلوغی سرور روبیکا با مشکل مواجه شد.", True)
963
 
964
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
965
 
 
967
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
968
  creds = get_user_credits(str_chat_id)
969
 
970
+ await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {model_name})", False)
971
 
972
+ job_id = None
973
+ # 🛑 پافشاری ۳۰ بار
974
+ for attempt in range(30):
975
+ async with aiohttp.ClientSession() as session:
976
+ form = aiohttp.FormData()
977
+ form.add_field('audio_file', src_bytes, filename='input.wav', content_type='audio/wav')
978
+ form.add_field('model_url', model_url)
979
+ form.add_field('pitch', str(pitch))
980
+ form.add_field('algo', 'rmvpe+')
981
+ form.add_field('index_inf', '0.75')
982
+ form.add_field('res_filter', '3')
983
+ form.add_field('env_ratio', '0.25')
984
+ form.add_field('protect', '0.33')
985
+ form.add_field('denoise', 'false')
986
+ form.add_field('reverb', 'false')
987
+ try:
988
+ async with session.post(f"{LEGACY_BASE_URL}/upload", data=form, timeout=120) as resp:
989
+ if resp.status == 429:
990
+ await asyncio.sleep(15)
991
+ continue
992
+ if resp.status == 200:
993
+ data = await resp.json()
994
+ job_id = data.get("job_id")
995
+ break
996
+ else:
997
+ await asyncio.sleep(5)
998
+ except Exception:
999
+ await asyncio.sleep(5)
1000
 
1001
+ if not job_id:
1002
+ return await send_with_keyboard(client, chat_id, "❌ ترافیک سرور بسیار بالاست. لطفا چند دقیقه دیگر امتحان کنید.", True)
1003
+
1004
+ await send_with_keyboard(client, chat_id, "✅ فایل ارسال شد. در حال پردازش و تغییر صدای شما...\n(لطفا چند دقیقه صبور باشید)", False)
1005
+
1006
+ final_filename = None
1007
+ async with aiohttp.ClientSession() as session:
1008
+ for _ in range(1000):
1009
  await asyncio.sleep(5)
1010
  try:
1011
+ async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=30) as c_resp:
1012
  if c_resp.status == 200:
1013
  c_data = await c_resp.json()
1014
  if c_data.get("status") == "completed":
 
1024
 
1025
  download_url = f"{LEGACY_BASE_URL}/download/{final_filename}"
1026
  await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
1027
+
1028
+ result_bytes = None
1029
+ for attempt in range(30):
1030
+ try:
1031
+ async with session.get(download_url, timeout=120) as d_resp:
1032
+ if d_resp.status == 200:
1033
+ result_bytes = await d_resp.read()
1034
+ break
1035
+ elif d_resp.status == 429:
1036
+ await asyncio.sleep(10)
1037
+ except Exception:
1038
+ await asyncio.sleep(5)
1039
+
1040
+ if not result_bytes:
1041
+ return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
1042
 
1043
  file_name_mp3 = f"vc_legacy_{uuid.uuid4().hex[:6]}.mp3"
1044
  await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
1045
 
1046
  upload_result = False
1047
+ for up_att in range(15):
1048
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ صدای خروجی با مدل {model_name} آماده است!")
1049
  if res is True:
1050
  upload_result = True
1051
  break
1052
+ await asyncio.sleep(5)
1053
 
1054
  if upload_result is True:
1055
  if not creds.get("is_premium"):
1056
  user_credits_db[str_chat_id]["voice_conv"] -= 1
1057
  save_db(user_credits_db)
1058
  else:
1059
+ await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما ترافیک روبیکا اجازه آپلود نداد.", True)
1060
 
1061
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1062
 
 
1246
  async with aiohttp.ClientSession() as session:
1247
  for key in keys_to_try_gemini:
1248
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1249
+ payload = {"contents":[{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
1250
  try:
1251
  async with session.post(url, json=payload, timeout=20) as response:
1252
  if response.status == 200:
 
1299
  proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
1300
 
1301
  generated_image = None
 
1302
 
1303
+ # پافشاری ۳۰ بار روی ساخت عکس
1304
+ for attempt in range(30):
1305
  keys_to_try = HF_TOKENS.copy()
1306
  random.shuffle(keys_to_try)
1307
  for token in keys_to_try:
 
1315
  )
1316
  break
1317
  except Exception as e:
1318
+ err_str = str(e).lower()
1319
+ if "429" in err_str or "too many" in err_str:
1320
+ await asyncio.sleep(10)
1321
  continue
1322
  if generated_image: break
1323
+ await asyncio.sleep(5)
1324
 
1325
  try:
1326
  if proc_msg:
 
1330
  except Exception: pass
1331
 
1332
  if not generated_image:
1333
+ return await send_with_keyboard(client, chat_id, f"❌ سرورهای ساخت عکس به شدت شلوغ هستند. لطفاً مجدداً امتحان کنید.", True)
1334
 
1335
  try:
1336
  file_name = f"image_{uuid.uuid4().hex}.jpg"
 
1339
  caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}"
1340
 
1341
  upload_result = False
1342
+ # پافشاری ۱۵ بار روی ارسال عکس به روبیکا
1343
+ for up_att in range(15):
1344
  res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
1345
  if res is True:
1346
  upload_result = True
1347
  break
1348
  else:
1349
+ await asyncio.sleep(5)
 
1350
 
1351
  if upload_result is True:
1352
  if not creds.get("is_premium"):
1353
  user_credits_db[str_chat_id]["image"] -= 1
1354
  save_db(user_credits_db)
1355
  else:
1356
+ await send_with_keyboard(client, chat_id, f"❌ عکس با موفقیت ساخته شد اما روبیکا به دلیل ترافیک بالا اجازه ارسال نداد.", True)
1357
 
1358
  if os.path.exists(file_name): os.remove(file_name)
1359
  except Exception as e:
1360
+ pass
1361
 
1362
  # ==============================================================================
1363
  # 🟢 پارت 15: توابع ترجمه و ویرایش عکس با هوش مصنوعی (Flux.2)
 
1484
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
1485
 
1486
  audio_bytes = None
 
1487
 
1488
+ # پافشاری بسیار بالا (۳۰ بار) برای سرورهای تولید صدا
1489
+ for attempt in range(30):
1490
  workers = WORKER_URLS.copy()
1491
  random.shuffle(workers)
1492
  async with aiohttp.ClientSession(headers=headers, timeout=aiohttp.ClientTimeout(total=600)) as session:
 
1498
  if 'audio' in content_type or response.content_length > 1000:
1499
  audio_bytes = await response.read()
1500
  break
1501
+ elif response.status == 429: # مسدودیت موقت
1502
+ await asyncio.sleep(10)
1503
+ except Exception:
 
1504
  continue
1505
  if audio_bytes: break
1506
+ await asyncio.sleep(5)
1507
 
1508
  try:
1509
  if proc_msg:
 
1518
  await asyncio.sleep(1)
1519
 
1520
  upload_result_file = False
1521
+ # پافشاری بالا روی ارسال فایل در روبیکا
1522
+ for up_att in range(15):
1523
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
1524
  if res is True:
1525
  upload_result_file = True
1526
  break
1527
  else:
1528
+ await asyncio.sleep(5)
 
1529
 
1530
  if upload_result_file is True:
1531
  if not creds.get("is_premium"):
1532
  user_credits_db[str_chat_id]["tts"] -= 1
1533
  save_db(user_credits_db)
1534
  else:
1535
+ await send_with_keyboard(client, chat_id, f"❌ صدای شما ساخته شد اما شلوغی سرور روبیکا مانع ارسال آن شد.", True)
1536
 
1537
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1538
  else:
1539
+ await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند. لطفا دقایقی دیگر مجددا امتحان کنید.", True)
1540
  except Exception: traceback.print_exc()
1541
 
1542
  # ==============================================================================
 
1992
  else:
1993
  bot = BotClient(bot_token)
1994
 
1995
+ # دکوریتور @bot.on_update حذف شد چون با وب‌هوک خودمان مستقیم این تابع را صدا می‌زنیم
1996
  async def main_handler(client, update):
1997
  global BOT_GUID
1998
 
 
2757
  except Exception: traceback.print_exc()
2758
 
2759
  if __name__ == "__main__":
2760
+ loop = asyncio.get_event_loop()
2761
+
2762
+ # 🟢 تونل‌های پرسرعت: ارتقا از 32 کارگر به 256 کارگر برای پاسخگویی همزمان به هزاران نفر
2763
+ loop.set_default_executor(concurrent.futures.ThreadPoolExecutor(max_workers=256))
2764
+
2765
+ # 🟢 روشن کردن سیستم پاکسازی هوشمند رم در پس‌زمینه
2766
+ loop.create_task(ram_garbage_collector())
2767
+
2768
+ # استارت کردن وب‌سرور فلسک در یک Thread جداگانه (که وب‌هوک را تنظیم و پیام‌ها را دریافت می‌کند)
2769
+ import threading
2770
  threading.Thread(target=run_flask, daemon=True).start()
2771
 
2772
  if bot_token:
2773
+ print("�� ربات آلفا پرو (نسخه صنعتی + وب‌هوک + دیتابیس هوشمند + پاکسازی رم + 256 تونل همزمان) روشن شد...")
2774
+ # جایگزینی bot.run() با روشن نگه داشتن حلقه بی‌نهایت
2775
+ try:
2776
+ loop.run_forever()
2777
+ except KeyboardInterrupt:
2778
+ pass