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

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +157 -267
main.py CHANGED
@@ -311,99 +311,16 @@ def to_english_digits(text):
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-sadarubikabot.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,15 +337,12 @@ def sync_read_file(file_name):
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
  # 🟢 پارت 7: کیبوردها (دکمه���های شیشه‌ای / منوها)
434
  # ==============================================================================
@@ -700,19 +614,22 @@ HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
700
  # ==============================================================================
701
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
702
  abs_path = os.path.abspath(file_name)
703
- error_logs =[]
704
 
705
- api_file_type = "Image" if file_type in ["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
706
 
 
707
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
708
  api_file_type = "Music"
709
  if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
710
  api_file_type = "Music"
711
 
712
- # --- فاز اول (تلاش با متدهای روب‌پای تا 15 بار) ---
713
- for attempt in range(15):
714
  try:
715
  sent_success = False
 
 
716
  if api_file_type == "Image" and hasattr(client, "send_photo"):
717
  try:
718
  await client.send_photo(chat_id, photo=abs_path, caption=caption)
@@ -721,6 +638,7 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
721
  await client.send_photo(chat_id, abs_path, caption=caption)
722
  sent_success = True
723
 
 
724
  elif api_file_type == "Voice" and hasattr(client, "send_voice"):
725
  try:
726
  await client.send_voice(chat_id, abs_path, caption=caption)
@@ -729,6 +647,7 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
729
  await client.send_voice(chat_id, file=abs_path, caption=caption)
730
  sent_success = True
731
 
 
732
  elif api_file_type == "Music" and hasattr(client, "send_music"):
733
  try:
734
  await client.send_music(chat_id, abs_path, caption=caption)
@@ -737,6 +656,8 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
737
  await client.send_music(chat_id, music=abs_path, caption=caption)
738
  sent_success = True
739
 
 
 
740
  if not sent_success:
741
  if hasattr(client, "send_document"):
742
  try:
@@ -758,34 +679,28 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
758
  return True
759
 
760
  except Exception as e:
761
- err_msg = str(e)
762
- error_logs.append(f"Rubpy Error: {err_msg[:50]}")
763
- # سیستم ضد اسپم روبیکا: اگر ارور محدودیت درخواست داد، ۱۵ ثانیه صبر کن!
764
- if "TOO_REQUESTS" in err_msg or "429" in err_msg or "502" in err_msg or "timeout" in err_msg.lower():
765
- await asyncio.sleep(15)
766
- else:
767
  await asyncio.sleep(4)
 
 
768
 
769
- # --- فاز دوم (سنگر آخر: آپلود دستی تا 30 بار پافشاری شدید) ---
770
- for attempt in range(30):
771
  try:
772
  url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
773
  url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
774
 
775
  async with aiohttp.ClientSession() as session:
776
- async with session.post(url_request, json={"type": api_file_type}, timeout=60) as resp:
777
  if resp.status != 200:
778
- await asyncio.sleep(5)
 
779
  continue
780
 
781
  req_data = await resp.json()
782
-
783
- # 🛑 هندل کردن دقیق ارور رباتیک TOO_REQUESTS
784
- if req_data.get("status") == "TOO_REQUESTS":
785
- error_logs.append("Hit TOO_REQUESTS on requestSendFile. Sleeping 15s...")
786
- await asyncio.sleep(15)
787
- continue
788
-
789
  if req_data.get("status") == "OK":
790
  upload_url = req_data.get("data", {}).get("upload_url")
791
  if upload_url:
@@ -794,24 +709,28 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
794
  form.add_field('file', f, filename=os.path.basename(abs_path))
795
  async with session.post(upload_url, data=form, timeout=300) as up_resp:
796
  if up_resp.status != 200:
797
- await asyncio.sleep(5)
 
 
 
 
798
  continue
799
 
800
  try:
801
  up_data = await up_resp.json()
802
- except Exception:
803
- await asyncio.sleep(3)
 
804
  continue
805
 
806
- if up_data.get("status") == "TOO_REQUESTS":
807
- await asyncio.sleep(15)
808
- continue
809
-
810
  final_file_id = None
811
 
 
 
812
  if up_data.get("status") == "INVALID_INPUT" and "format" in str(up_data).lower():
813
  api_file_type = "File"
814
- await asyncio.sleep(2)
 
815
  continue
816
 
817
  if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
@@ -828,26 +747,34 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
828
  "chat_keypad_type": "New",
829
  "chat_keypad": MAIN_KEYPAD_DICT
830
  }
831
- async with session.post(url_send, json=send_payload, timeout=60) as send_resp:
832
- s_data = await send_resp.json()
833
- if s_data.get("status") == "TOO_REQUESTS":
834
- await asyncio.sleep(15)
835
  continue
836
- if s_data.get("status") == "OK":
837
- return True
 
 
838
  else:
839
  if up_data.get("status") == "INVALID_INPUT" and api_file_type in ["Voice", "Music"]:
840
- api_file_type = "File"
 
 
 
841
  except Exception as e:
842
- error_logs.append(f"Raw HTTP Error: {str(e)[:50]}")
843
- await asyncio.sleep(5)
844
 
845
  return "\n".join(error_logs[-6:])
846
 
847
  # ==============================================================================
848
  # 🟢 پارت 12: توابع تغییر صدا و لیست گویندگان
849
  # ==============================================================================
850
- WORKER_URLS = ["https://opera8-ttspro.hf.space/generate"]
 
 
 
851
 
852
  SPEAKERS = {
853
  "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
@@ -864,100 +791,80 @@ SPEAKERS = {
864
 
865
  user_states = {}
866
 
 
 
 
867
  async def process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, job_type_name, credit_type):
868
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
869
  creds = get_user_credits(str_chat_id)
870
 
871
- await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {job_type_name})", False)
872
-
873
- job_id = None
874
- total_chunks = 1
875
- chunks =[]
876
-
877
- # 🛑 پافشاری ۳۰ بار برای آپلود به سرور تغییر صدا (ضد ارور 429)
878
- for attempt in range(30):
879
- async with aiohttp.ClientSession() as session:
880
- # فرم باید در هر تلاش از نو ساخته شود
881
- form = aiohttp.FormData()
882
- form.add_field('source_audio', src_bytes, filename='src.wav', content_type='audio/wav')
883
- form.add_field('ref_audio', ref_bytes, filename='ref.wav', content_type='audio/wav')
884
- try:
885
- async with session.post(f"{VC_BASE_URL}/upload", data=form, timeout=120) as resp:
886
- if resp.status == 429: # شلوغی سرور اسپیس
887
- await asyncio.sleep(15)
888
- continue
889
- if resp.status == 200:
890
- data = await resp.json()
891
- job_id = data.get("job_id")
892
- total_chunks = data.get("total_chunks", 1)
893
- chunks = data.get("chunks",[])
894
- break
895
- else:
896
- await asyncio.sleep(5)
897
- except Exception:
898
- await asyncio.sleep(5)
899
-
900
- if not job_id:
901
- return await send_with_keyboard(client, chat_id, "❌ پردازش ناموفق بود. ترافیک ربات بسیار بالاست، لطفا چند دقیقه دیگر مجدداً تلاش کنید.", True)
902
-
903
- await send_with_keyboard(client, chat_id, "✅ فایل‌ها ارسال شد. در حال پردازش و تغییر صدا...\n(لطفا چند دقیقه صبور باشید)", False)
904
 
905
- final_filename = None
906
  async with aiohttp.ClientSession() as session:
907
- for _ in range(1000): # حلقه بی‌نهایت چک کردن استتوس
908
- await asyncio.sleep(5)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
909
  payload_check = {"job_id": job_id, "total_chunks": total_chunks, "chunks": chunks}
910
  try:
911
- async with session.post(f"{VC_BASE_URL}/check_status", json=payload_check, timeout=30) as c_resp:
912
  if c_resp.status == 200:
913
  c_data = await c_resp.json()
914
  if c_data.get("status") == "completed":
915
  final_filename = c_data.get("filename")
916
  break
917
  elif c_data.get("status") in ["failed", "error"]:
918
- return await send_with_keyboard(client, chat_id, "❌ خطای داخلی سرور در حین ساخت صدا رخ داد.", True)
919
  except Exception:
920
  pass
921
 
922
  if not final_filename:
923
- return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید.", True)
924
 
925
  download_url = f"{VC_BASE_URL}/download/{final_filename}"
926
  await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
927
-
928
- result_bytes = None
929
- for attempt in range(30):
930
- try:
931
- async with session.get(download_url, timeout=120) as d_resp:
932
- if d_resp.status == 200:
933
- result_bytes = await d_resp.read()
934
- break
935
- elif d_resp.status == 429:
936
- await asyncio.sleep(10)
937
- except Exception:
938
- await asyncio.sleep(5)
939
-
940
- if not result_bytes:
941
- return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
942
 
943
  file_name_mp3 = f"vc_standard_{uuid.uuid4().hex[:6]}.mp3"
944
  await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
945
 
946
  upload_result = False
947
- # پافشاری بسیار بالا برای آپلود نهایی به روبیکا
948
- for up_att in range(15):
949
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ {job_type_name} شما آماده است!")
950
  if res is True:
951
  upload_result = True
952
  break
953
- await asyncio.sleep(5)
954
 
955
  if upload_result is True:
956
  if not creds.get("is_premium"):
957
  user_credits_db[str_chat_id][credit_type] -= 1
958
  save_db(user_credits_db)
959
  else:
960
- await send_with_keyboard(client, chat_id, "❌ فایل با موفقیت پردازش شد اما ارسال آن به دلیل شلوغی سرور روبیکا با مشکل مواجه شد.", True)
961
 
962
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
963
 
@@ -965,48 +872,37 @@ async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, mo
965
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
966
  creds = get_user_credits(str_chat_id)
967
 
968
- await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {model_name})", False)
969
-
970
- job_id = None
971
- # 🛑 پافشاری ۳۰ بار
972
- for attempt in range(30):
973
- async with aiohttp.ClientSession() as session:
974
- form = aiohttp.FormData()
975
- form.add_field('audio_file', src_bytes, filename='input.wav', content_type='audio/wav')
976
- form.add_field('model_url', model_url)
977
- form.add_field('pitch', str(pitch))
978
- form.add_field('algo', 'rmvpe+')
979
- form.add_field('index_inf', '0.75')
980
- form.add_field('res_filter', '3')
981
- form.add_field('env_ratio', '0.25')
982
- form.add_field('protect', '0.33')
983
- form.add_field('denoise', 'false')
984
- form.add_field('reverb', 'false')
985
- try:
986
- async with session.post(f"{LEGACY_BASE_URL}/upload", data=form, timeout=120) as resp:
987
- if resp.status == 429:
988
- await asyncio.sleep(15)
989
- continue
990
- if resp.status == 200:
991
- data = await resp.json()
992
- job_id = data.get("job_id")
993
- break
994
- else:
995
- await asyncio.sleep(5)
996
- except Exception:
997
- await asyncio.sleep(5)
998
-
999
- if not job_id:
1000
- return await send_with_keyboard(client, chat_id, "❌ ترافیک سرور بسیار بالاست. لطفا چند دقیقه دیگر امتحان کنید.", True)
1001
-
1002
- await send_with_keyboard(client, chat_id, "✅ فایل ارسال شد. در حال پردازش و تغییر صدای شما...\n(لطفا چند دقیقه صبور باشید)", False)
1003
 
1004
- final_filename = None
1005
  async with aiohttp.ClientSession() as session:
1006
- for _ in range(1000):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1007
  await asyncio.sleep(5)
1008
  try:
1009
- async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=30) as c_resp:
1010
  if c_resp.status == 200:
1011
  c_data = await c_resp.json()
1012
  if c_data.get("status") == "completed":
@@ -1022,39 +918,32 @@ async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, mo
1022
 
1023
  download_url = f"{LEGACY_BASE_URL}/download/{final_filename}"
1024
  await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
1025
-
1026
- result_bytes = None
1027
- for attempt in range(30):
1028
- try:
1029
- async with session.get(download_url, timeout=120) as d_resp:
1030
- if d_resp.status == 200:
1031
- result_bytes = await d_resp.read()
1032
- break
1033
- elif d_resp.status == 429:
1034
- await asyncio.sleep(10)
1035
- except Exception:
1036
- await asyncio.sleep(5)
1037
-
1038
- if not result_bytes:
1039
- return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
1040
 
1041
  file_name_mp3 = f"vc_legacy_{uuid.uuid4().hex[:6]}.mp3"
1042
  await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
1043
 
1044
  upload_result = False
1045
- for up_att in range(15):
1046
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ صدای خروجی با مدل {model_name} آماده است!")
1047
  if res is True:
1048
  upload_result = True
1049
  break
1050
- await asyncio.sleep(5)
1051
 
1052
  if upload_result is True:
1053
  if not creds.get("is_premium"):
1054
  user_credits_db[str_chat_id]["voice_conv"] -= 1
1055
  save_db(user_credits_db)
1056
  else:
1057
- await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما ترافیک روبیکا اجازه آپلود نداد.", True)
1058
 
1059
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1060
 
@@ -1244,7 +1133,7 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1244
  async with aiohttp.ClientSession() as session:
1245
  for key in keys_to_try_gemini:
1246
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1247
- payload = {"contents":[{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
1248
  try:
1249
  async with session.post(url, json=payload, timeout=20) as response:
1250
  if response.status == 200:
@@ -1297,9 +1186,9 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1297
  proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
1298
 
1299
  generated_image = None
 
1300
 
1301
- # پافشاری ۳۰ بار روی ساخت عکس
1302
- for attempt in range(30):
1303
  keys_to_try = HF_TOKENS.copy()
1304
  random.shuffle(keys_to_try)
1305
  for token in keys_to_try:
@@ -1313,12 +1202,10 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1313
  )
1314
  break
1315
  except Exception as e:
1316
- err_str = str(e).lower()
1317
- if "429" in err_str or "too many" in err_str:
1318
- await asyncio.sleep(10)
1319
  continue
1320
  if generated_image: break
1321
- await asyncio.sleep(5)
1322
 
1323
  try:
1324
  if proc_msg:
@@ -1328,7 +1215,7 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1328
  except Exception: pass
1329
 
1330
  if not generated_image:
1331
- return await send_with_keyboard(client, chat_id, f"❌ سرورهای ساخت عکس به شدت شلوغ هستند. لطفاً مجدداً امتحان کنید.", True)
1332
 
1333
  try:
1334
  file_name = f"image_{uuid.uuid4().hex}.jpg"
@@ -1337,25 +1224,26 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
1337
  caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}"
1338
 
1339
  upload_result = False
1340
- # پافشاری ۱۵ بار روی ارسال عکس به روبیکا
1341
- for up_att in range(15):
1342
  res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
1343
  if res is True:
1344
  upload_result = True
1345
  break
1346
  else:
1347
- await asyncio.sleep(5)
 
1348
 
1349
  if upload_result is True:
1350
  if not creds.get("is_premium"):
1351
  user_credits_db[str_chat_id]["image"] -= 1
1352
  save_db(user_credits_db)
1353
  else:
1354
- await send_with_keyboard(client, chat_id, f"❌ عکس با موفقیت ساخته شد اما روبیکا به دلیل ترافیک بالا اجازه ارسال نداد.", True)
1355
 
1356
  if os.path.exists(file_name): os.remove(file_name)
1357
  except Exception as e:
1358
- pass
1359
 
1360
  # ==============================================================================
1361
  # 🟢 پارت 15: توابع ترجمه و ویرایش عکس با هوش مصنوعی (Flux.2)
@@ -1482,9 +1370,9 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1482
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
1483
 
1484
  audio_bytes = None
 
1485
 
1486
- # پافشاری بسیار بالا (۳۰ بار) برای سرورهای تولید صدا
1487
- for attempt in range(30):
1488
  workers = WORKER_URLS.copy()
1489
  random.shuffle(workers)
1490
  async with aiohttp.ClientSession(headers=headers, timeout=aiohttp.ClientTimeout(total=600)) as session:
@@ -1496,12 +1384,13 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1496
  if 'audio' in content_type or response.content_length > 1000:
1497
  audio_bytes = await response.read()
1498
  break
1499
- elif response.status == 429: # مسدودیت موقت
1500
- await asyncio.sleep(10)
1501
- except Exception:
 
1502
  continue
1503
  if audio_bytes: break
1504
- await asyncio.sleep(5)
1505
 
1506
  try:
1507
  if proc_msg:
@@ -1516,25 +1405,26 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1516
  await asyncio.sleep(1)
1517
 
1518
  upload_result_file = False
1519
- # پافشاری بالا روی ارسال فایل در روبیکا
1520
- for up_att in range(15):
1521
  res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
1522
  if res is True:
1523
  upload_result_file = True
1524
  break
1525
  else:
1526
- await asyncio.sleep(5)
 
1527
 
1528
  if upload_result_file is True:
1529
  if not creds.get("is_premium"):
1530
  user_credits_db[str_chat_id]["tts"] -= 1
1531
  save_db(user_credits_db)
1532
  else:
1533
- await send_with_keyboard(client, chat_id, f"❌ صدای شما ساخته شد اما شلوغی سرور روبیکا مانع ارسال آن شد.", True)
1534
 
1535
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1536
  else:
1537
- await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند. لطفا دقایقی دیگر مجددا امتحان کنید.", True)
1538
  except Exception: traceback.print_exc()
1539
 
1540
  # ==============================================================================
 
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
  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
  # ==============================================================================
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
  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
  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
  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
  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
  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
  "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
 
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
  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
 
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
  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
  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
  )
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
  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
  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
  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
  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
  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
  # ==============================================================================