Update main.py
Browse files
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
def home():
|
| 321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
# --- فاز اول (
|
| 628 |
-
for attempt in range(
|
| 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)
|
| 683 |
-
error_logs.append(f"Rubpy
|
| 684 |
-
|
| 685 |
-
if "
|
| 686 |
-
await asyncio.sleep(
|
| 687 |
else:
|
| 688 |
-
await asyncio.sleep(
|
| 689 |
|
| 690 |
-
# --- فاز دوم (سنگر آخر
|
| 691 |
-
for attempt in range(
|
| 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=
|
| 698 |
if resp.status != 200:
|
| 699 |
-
|
| 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 |
-
|
| 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
|
| 722 |
-
|
| 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 |
-
|
| 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=
|
| 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") == "
|
| 758 |
-
|
|
|
|
|
|
|
|
|
|
| 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)[:
|
| 767 |
-
await asyncio.sleep(
|
| 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 |
-
|
| 802 |
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 818 |
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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=
|
| 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, "❌ خطای سرور در حین
|
| 834 |
except Exception:
|
| 835 |
pass
|
| 836 |
|
| 837 |
if not final_filename:
|
| 838 |
-
return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید
|
| 839 |
|
| 840 |
download_url = f"{VC_BASE_URL}/download/{final_filename}"
|
| 841 |
await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
| 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(
|
| 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, "❌ فایل پردازش شد اما ا
|
| 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 |
-
|
| 876 |
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
-
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 898 |
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 903 |
await asyncio.sleep(5)
|
| 904 |
try:
|
| 905 |
-
async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=
|
| 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 |
-
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
|
| 925 |
-
|
| 926 |
-
|
| 927 |
-
|
| 928 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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(
|
| 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(
|
| 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, "❌ فایل پردازش شد اما ا
|
| 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":
|
| 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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
| 1206 |
continue
|
| 1207 |
if generated_image: break
|
| 1208 |
-
await asyncio.sleep(
|
| 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"❌
|
| 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 |
-
|
| 1228 |
-
for up_att in range(
|
| 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 |
-
|
| 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"❌ عکس ساخته شد اما
|
| 1243 |
|
| 1244 |
if os.path.exists(file_name): os.remove(file_name)
|
| 1245 |
except Exception as e:
|
| 1246 |
-
|
| 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 |
-
|
|
|
|
| 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 |
-
|
| 1388 |
-
|
| 1389 |
-
except Exception
|
| 1390 |
-
last_error = f"خطا: {str(e)}"
|
| 1391 |
continue
|
| 1392 |
if audio_bytes: break
|
| 1393 |
-
await asyncio.sleep(
|
| 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 |
-
|
| 1409 |
-
for up_att in range(
|
| 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 |
-
|
| 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"❌
|
| 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"❌ سرورها درگیر هستند.
|
| 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
|
| 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 |
-
|
| 2652 |
-
|
| 2653 |
-
|
| 2654 |
-
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|