Update main.py
Browse files
main.py
CHANGED
|
@@ -16,36 +16,52 @@ import concurrent.futures
|
|
| 16 |
from flask import Flask
|
| 17 |
from rubpy.bot import BotClient, filters
|
| 18 |
|
| 19 |
-
# ایمپورتهای جدید برای هوش مصنوعی، کار با فایل صوتی و دیتابیس هاگینگ فیس
|
| 20 |
from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download
|
| 21 |
from PIL import Image
|
| 22 |
from pydub import AudioSegment
|
| 23 |
|
| 24 |
-
# ---
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
#
|
|
|
|
| 28 |
BOT_GUID = None
|
| 29 |
|
| 30 |
# =======================================================
|
| 31 |
-
#
|
| 32 |
# =======================================================
|
| 33 |
user_message_times = {}
|
| 34 |
|
| 35 |
def is_user_spamming(chat_id):
|
| 36 |
now = time.time()
|
| 37 |
times = user_message_times.get(chat_id,[])
|
| 38 |
-
|
| 39 |
-
times =[t for t in times if now - t < 3.0]
|
| 40 |
times.append(now)
|
| 41 |
user_message_times[chat_id] = times
|
| 42 |
-
|
| 43 |
-
# اگر یک کاربر به تنهایی در 3 ثانیه بیش از 4 پیام داد، پیامش نادیده گرفته شود
|
| 44 |
if len(times) > 4:
|
| 45 |
return True
|
| 46 |
return False
|
| 47 |
|
| 48 |
-
# --- سیستم دیتابیس حساب کاربری
|
| 49 |
DB_FILE = "users_db.json"
|
| 50 |
DATASET_REPO = "opera8/Karbaran-rayegan-tedad"
|
| 51 |
HF_TOKEN_DB = os.environ.get("HF_TOKEN")
|
|
@@ -72,7 +88,16 @@ def gregorian_to_jalali(gy, gm, gd):
|
|
| 72 |
|
| 73 |
def load_db():
|
| 74 |
print("در حال تلاش برای خواندن دیتابیس کاربران از دیتاست هاگینگ فیس...")
|
| 75 |
-
if HF_TOKEN_DB:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
try:
|
| 77 |
file_path = hf_hub_download(
|
| 78 |
repo_id=DATASET_REPO,
|
|
@@ -84,15 +109,13 @@ def load_db():
|
|
| 84 |
print("✅ دیتابیس با موفقیت از دیتاست هاگینگ فیس لود شد.")
|
| 85 |
return json.load(f)
|
| 86 |
except Exception as e:
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
pass
|
| 95 |
-
return {}
|
| 96 |
|
| 97 |
db_needs_upload = False
|
| 98 |
|
|
@@ -101,21 +124,19 @@ def save_db(db_data):
|
|
| 101 |
with db_lock:
|
| 102 |
try:
|
| 103 |
with open(DB_FILE, "w", encoding="utf-8") as f:
|
| 104 |
-
json.dump(db_data, f, ensure_ascii=False,
|
| 105 |
-
db_needs_upload = True
|
| 106 |
except Exception as e:
|
| 107 |
print("خطا در ذخیره دیتابیس:", e)
|
| 108 |
|
| 109 |
-
# یک تسک پسزمینه برای آپلود منظم و بدون فشار به سرور
|
| 110 |
async def background_db_uploader():
|
| 111 |
global db_needs_upload
|
| 112 |
while True:
|
| 113 |
-
await asyncio.sleep(300)
|
| 114 |
if db_needs_upload and HF_TOKEN_DB:
|
| 115 |
db_needs_upload = False
|
| 116 |
api = HfApi(token=HF_TOKEN_DB)
|
| 117 |
try:
|
| 118 |
-
# استفاده از to_thread برای جلوگیری از قفل شدن ربات
|
| 119 |
await asyncio.to_thread(
|
| 120 |
api.upload_file,
|
| 121 |
path_or_fileobj=DB_FILE,
|
|
@@ -126,7 +147,7 @@ async def background_db_uploader():
|
|
| 126 |
print("✅ بکاپ دیتابیس در هاگینگ فیس ذخیره شد.")
|
| 127 |
except Exception as e:
|
| 128 |
print("❌ خطا در آپلود دیتابیس به هاگینگ فیس:", str(e)[:100])
|
| 129 |
-
db_needs_upload = True
|
| 130 |
|
| 131 |
user_credits_db = load_db()
|
| 132 |
|
|
@@ -135,7 +156,6 @@ def get_or_create_referral_code(chat_id):
|
|
| 135 |
if not user_data.get("referral_code"):
|
| 136 |
while True:
|
| 137 |
new_code = ''.join(random.choices(string.digits, k=8))
|
| 138 |
-
# در اینجا بررسی میکنیم مقدار دیتابیس حتما دیکشنری (کاربر) باشد و نه لیست پردازش پیام ها
|
| 139 |
exists = any(isinstance(u, dict) and u.get("referral_code") == new_code for u in user_credits_db.values())
|
| 140 |
if not exists:
|
| 141 |
user_data["referral_code"] = new_code
|
|
@@ -166,6 +186,9 @@ def get_user_credits(chat_id):
|
|
| 166 |
"tts": 5,
|
| 167 |
"file": 1,
|
| 168 |
"stt": 5,
|
|
|
|
|
|
|
|
|
|
| 169 |
"has_joined": False,
|
| 170 |
"invited_count": 0,
|
| 171 |
"used_referral": False,
|
|
@@ -174,6 +197,11 @@ def get_user_credits(chat_id):
|
|
| 174 |
save_db(user_credits_db)
|
| 175 |
|
| 176 |
user_data = user_credits_db[str_chat_id]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
is_premium = user_data.get("is_premium", False)
|
| 178 |
|
| 179 |
if is_premium and user_data.get("expire_date"):
|
|
@@ -196,13 +224,14 @@ def get_user_credits(chat_id):
|
|
| 196 |
user_data["tts"] = 5
|
| 197 |
user_data["file"] = 1
|
| 198 |
user_data["stt"] = 5
|
|
|
|
|
|
|
| 199 |
save_db(user_credits_db)
|
| 200 |
|
| 201 |
return user_data
|
| 202 |
|
| 203 |
def to_english_digits(text):
|
| 204 |
-
if not text:
|
| 205 |
-
return text
|
| 206 |
persian_digits = '۰۱۲۳۴۵۶۷۸۹'
|
| 207 |
arabic_digits = '٠١٢٣٤٥٦٧٨٩'
|
| 208 |
english_digits = '0123456789'
|
|
@@ -214,12 +243,12 @@ app = Flask(__name__)
|
|
| 214 |
|
| 215 |
@app.route('/')
|
| 216 |
def home():
|
| 217 |
-
return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دعوت دوستان + سیستم
|
| 218 |
|
| 219 |
def run_flask():
|
| 220 |
app.run(host="0.0.0.0", port=7860, threaded=True)
|
| 221 |
|
| 222 |
-
# --- توابع کمکی
|
| 223 |
def sync_save_image(image, file_name):
|
| 224 |
rgb_im = image.convert('RGB')
|
| 225 |
rgb_im.save(file_name, format="JPEG", quality=100)
|
|
@@ -259,6 +288,12 @@ MAIN_KEYPAD_DICT = {
|
|
| 259 |
{"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا🗣️"}
|
| 260 |
]
|
| 261 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
{
|
| 263 |
"buttons":[
|
| 264 |
{"id": "stt_btn", "type": "Simple", "button_text": "فایل صوتی به متن 📝"},
|
|
@@ -332,78 +367,54 @@ async def check_channel_membership(client, user_id):
|
|
| 332 |
elif hasattr(res, 'exist') and hasattr(res.exist, 'chat'):
|
| 333 |
CHANNEL_GUID = getattr(res.exist.chat, 'object_guid', None)
|
| 334 |
|
| 335 |
-
if not CHANNEL_GUID:
|
| 336 |
-
return True
|
| 337 |
|
| 338 |
-
payload = {
|
| 339 |
-
"channel_guid": CHANNEL_GUID,
|
| 340 |
-
"member_guid": user_id
|
| 341 |
-
}
|
| 342 |
res = await client._make_request("getChannelParticipant", payload)
|
| 343 |
|
| 344 |
-
if isinstance(res, dict):
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
elif hasattr(res, 'status'):
|
| 350 |
-
if getattr(res, 'status') == "OK":
|
| 351 |
-
return True
|
| 352 |
-
|
| 353 |
-
return False
|
| 354 |
-
except Exception:
|
| 355 |
return False
|
|
|
|
| 356 |
|
| 357 |
async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
|
| 358 |
try:
|
| 359 |
-
if not use_keyboard:
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
payload = {
|
| 363 |
-
"chat_id": chat_id,
|
| 364 |
-
"text": text,
|
| 365 |
-
"chat_keypad_type": "New",
|
| 366 |
-
"chat_keypad": MAIN_KEYPAD_DICT
|
| 367 |
-
}
|
| 368 |
return await client._make_request("sendMessage", payload)
|
| 369 |
except Exception:
|
| 370 |
-
try:
|
| 371 |
-
|
| 372 |
-
except Exception:
|
| 373 |
-
return None
|
| 374 |
-
|
| 375 |
|
| 376 |
bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
|
| 377 |
|
| 378 |
# ==================================================================
|
| 379 |
-
#
|
| 380 |
# ==================================================================
|
| 381 |
async def helper_download_file(client, msg_obj):
|
| 382 |
errors =[]
|
| 383 |
file_obj = None
|
| 384 |
file_id = None
|
| 385 |
|
| 386 |
-
# 1. استخراج آبجکت و آیدی فایل با دقت بالا
|
| 387 |
for attr in['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']:
|
| 388 |
val = getattr(msg_obj, attr, None)
|
| 389 |
if val:
|
| 390 |
file_obj = val
|
| 391 |
-
if hasattr(val, 'file_id'):
|
| 392 |
-
|
| 393 |
-
elif isinstance(val, dict) and 'file_id' in val:
|
| 394 |
-
file_id = val['file_id']
|
| 395 |
break
|
| 396 |
|
| 397 |
if not file_obj and hasattr(msg_obj, "file_id"):
|
| 398 |
file_id = msg_obj.file_id
|
| 399 |
file_obj = msg_obj
|
| 400 |
|
| 401 |
-
if not file_id:
|
| 402 |
-
raise Exception("خطا: هیچ فایلی در پیام یافت نشد.")
|
| 403 |
|
| 404 |
temp_name = f"temp_dl_{uuid.uuid4().hex}.tmp"
|
| 405 |
|
| 406 |
-
# روش 1: استفاده مستقیم از API قدرتمند روبیکا با پافشاری بسیار بالا (20 بار)
|
| 407 |
for attempt in range(20):
|
| 408 |
try:
|
| 409 |
url_get_file = f"https://botapi.rubika.ir/v3/{bot_token}/getFile"
|
|
@@ -417,27 +428,22 @@ async def helper_download_file(client, msg_obj):
|
|
| 417 |
if res_data.get("status") == "OK" or res_data.get("status_det") == "OK":
|
| 418 |
download_url = res_data.get("data", {}).get("download_url") or res_data.get("data", {}).get("file_url")
|
| 419 |
if download_url:
|
| 420 |
-
# اگر لینک داد، 3 بار هم برای خود لینک تلاش میکنیم تا اگر قطع شد جبران شود
|
| 421 |
for dl_attempt in range(3):
|
| 422 |
try:
|
| 423 |
async with session.get(download_url, headers=headers, timeout=60) as dl_resp:
|
| 424 |
if dl_resp.status == 200:
|
| 425 |
data = await dl_resp.read()
|
| 426 |
-
if data and len(data) > 0:
|
| 427 |
-
|
| 428 |
-
else:
|
| 429 |
-
errors.append(f"DL HTTP {dl_resp.status}")
|
| 430 |
await asyncio.sleep(2)
|
| 431 |
except Exception as dl_err:
|
| 432 |
errors.append(f"DL Error: {str(dl_err)[:30]}")
|
| 433 |
await asyncio.sleep(2)
|
| 434 |
-
else:
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
errors.append(f"API Not OK: {res_data.get('status')}")
|
| 438 |
-
elif resp.status in[502, 503, 500]:
|
| 439 |
errors.append(f"GetFile HTTP {resp.status}")
|
| 440 |
-
await asyncio.sleep(3.5)
|
| 441 |
continue
|
| 442 |
else:
|
| 443 |
errors.append(f"GetFile HTTP {resp.status}")
|
|
@@ -446,25 +452,20 @@ async def helper_download_file(client, msg_obj):
|
|
| 446 |
errors.append(f"API Error: {str(e)[:50]}")
|
| 447 |
await asyncio.sleep(2)
|
| 448 |
|
| 449 |
-
# روش 2: کتابخانه rubpy (بکآپ با 10 بار پافشاری)
|
| 450 |
if file_obj:
|
| 451 |
for attempt in range(10):
|
| 452 |
try:
|
| 453 |
if hasattr(client, "download"):
|
| 454 |
result = await client.download(file_obj, save_as=temp_name)
|
| 455 |
-
if isinstance(result, bytes) and len(result) > 0:
|
| 456 |
-
return result
|
| 457 |
if os.path.exists(temp_name):
|
| 458 |
data = await asyncio.to_thread(sync_read_file, temp_name)
|
| 459 |
os.remove(temp_name)
|
| 460 |
-
if data and len(data) > 0:
|
| 461 |
-
return data
|
| 462 |
except Exception as e:
|
| 463 |
-
|
| 464 |
-
errors.append(f"Rubpy Obj Error: {err_str[:50]}")
|
| 465 |
await asyncio.sleep(3)
|
| 466 |
|
| 467 |
-
# روش 3: متد قدیمی rubpy (بکآپ نهایی با 5 بار پافشاری)
|
| 468 |
for attempt in range(5):
|
| 469 |
try:
|
| 470 |
if hasattr(client, "download_file"):
|
|
@@ -472,23 +473,33 @@ async def helper_download_file(client, msg_obj):
|
|
| 472 |
if os.path.exists(temp_name):
|
| 473 |
data = await asyncio.to_thread(sync_read_file, temp_name)
|
| 474 |
os.remove(temp_name)
|
| 475 |
-
if data and len(data) > 0:
|
| 476 |
-
return data
|
| 477 |
except Exception as e:
|
| 478 |
errors.append(f"Rubpy FileId Error: {str(e)[:50]}")
|
| 479 |
await asyncio.sleep(3)
|
| 480 |
|
| 481 |
raise Exception(f"سرورهای دانلود روبیکا پس از ۳۵ بار تلاش پاسخ ندادند!\nلاگ خطاها: {str(errors[-5:])}")
|
| 482 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
|
|
|
|
|
|
|
|
|
|
| 484 |
GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "")
|
| 485 |
GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "")
|
| 486 |
|
| 487 |
_raw_keys =[]
|
| 488 |
-
if GEMINI_KEYS_STR1:
|
| 489 |
-
|
| 490 |
-
if GEMINI_KEYS_STR2:
|
| 491 |
-
_raw_keys.extend(GEMINI_KEYS_STR2.split(","))
|
| 492 |
|
| 493 |
GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()]))
|
| 494 |
print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.")
|
|
@@ -500,46 +511,34 @@ def get_next_gemini_keys(count=100):
|
|
| 500 |
global current_gemini_key_index
|
| 501 |
with gemini_key_lock:
|
| 502 |
total_keys = len(GEMINI_KEYS)
|
| 503 |
-
if total_keys == 0:
|
| 504 |
-
return[]
|
| 505 |
-
|
| 506 |
actual_count = min(count, total_keys)
|
| 507 |
selected_keys =[]
|
| 508 |
-
|
| 509 |
for _ in range(actual_count):
|
| 510 |
selected_keys.append(GEMINI_KEYS[current_gemini_key_index])
|
| 511 |
current_gemini_key_index = (current_gemini_key_index + 1) % total_keys
|
| 512 |
-
|
| 513 |
return selected_keys
|
| 514 |
|
| 515 |
HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
|
| 516 |
HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
|
| 517 |
|
| 518 |
-
|
| 519 |
# ==================================================================
|
| 520 |
-
#
|
| 521 |
# ==================================================================
|
| 522 |
async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
|
| 523 |
abs_path = os.path.abspath(file_name)
|
| 524 |
error_logs =[]
|
| 525 |
|
| 526 |
-
|
| 527 |
-
api_file_type = "
|
| 528 |
-
|
| 529 |
-
# روبیکا با ارسال فایلهای ogg غیر ویس و فایلهای mp3 به عنوان File مشکل دارد و 502 میدهد.
|
| 530 |
-
if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
|
| 531 |
-
api_file_type = "Music"
|
| 532 |
-
if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
|
| 533 |
-
api_file_type = "Music"
|
| 534 |
|
| 535 |
-
# روش اول: استفاده مستقیم از API روبیکا با 15 بار پافشاری قدرتمند
|
| 536 |
for attempt in range(15):
|
| 537 |
try:
|
| 538 |
url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
|
| 539 |
url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
|
| 540 |
|
| 541 |
async with aiohttp.ClientSession() as session:
|
| 542 |
-
# 1. درخواست لینک آپلود
|
| 543 |
async with session.post(url_request, json={"type": api_file_type}, timeout=30) as resp:
|
| 544 |
if resp.status != 200:
|
| 545 |
error_logs.append(f"Request HTTP {resp.status}")
|
|
@@ -547,39 +546,29 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
|
|
| 547 |
continue
|
| 548 |
|
| 549 |
req_data = await resp.json()
|
| 550 |
-
|
| 551 |
if req_data.get("status") == "OK":
|
| 552 |
upload_url = req_data.get("data", {}).get("upload_url")
|
| 553 |
-
|
| 554 |
if upload_url:
|
| 555 |
with open(abs_path, "rb") as f:
|
| 556 |
form = aiohttp.FormData()
|
| 557 |
form.add_field('file', f, filename=os.path.basename(abs_path))
|
| 558 |
-
|
| 559 |
-
# 2. آپلود فایل در سرور (با تایماوت 300 ثانیه مخصوص فایلهای حجیم مثل پادکست)
|
| 560 |
async with session.post(upload_url, data=form, timeout=300) as up_resp:
|
| 561 |
if up_resp.status != 200:
|
| 562 |
error_logs.append(f"Upload HTTP {up_resp.status}")
|
| 563 |
-
if up_resp.status in[502, 503, 500]
|
| 564 |
-
await asyncio.sleep(3)
|
| 565 |
-
else:
|
| 566 |
-
await asyncio.sleep(1.5)
|
| 567 |
continue
|
| 568 |
|
| 569 |
-
try:
|
| 570 |
-
up_data = await up_resp.json()
|
| 571 |
except Exception as json_err:
|
| 572 |
error_logs.append(f"JSON Decode Error: {json_err}")
|
| 573 |
await asyncio.sleep(2)
|
| 574 |
continue
|
| 575 |
|
| 576 |
-
# 3. دریافت آیدی و ارسال نهایی پیام
|
| 577 |
final_file_id = None
|
| 578 |
if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
|
| 579 |
if "data" in up_data and isinstance(up_data["data"], dict):
|
| 580 |
final_file_id = up_data["data"].get("file_id") or up_data["data"].get("id")
|
| 581 |
-
elif "file_id" in up_data:
|
| 582 |
-
final_file_id = up_data.get("file_id")
|
| 583 |
|
| 584 |
if final_file_id:
|
| 585 |
send_payload = {
|
|
@@ -596,48 +585,53 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
|
|
| 596 |
continue
|
| 597 |
|
| 598 |
s_data = await send_resp.json()
|
| 599 |
-
if s_data.get("status") == "OK":
|
| 600 |
-
|
| 601 |
-
else:
|
| 602 |
-
error_logs.append(f"SendFile API Error: {s_data}")
|
| 603 |
else:
|
| 604 |
if up_data.get("status") == "INVALID_INPUT" and api_file_type == "Voice":
|
| 605 |
api_file_type = "Music"
|
| 606 |
error_logs.append(f"Upload API Error: {up_data}")
|
| 607 |
-
else:
|
| 608 |
-
|
| 609 |
-
else:
|
| 610 |
-
error_logs.append(f"Request API Error: {req_data}")
|
| 611 |
except Exception as e:
|
| 612 |
error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
|
| 613 |
await asyncio.sleep(2.5)
|
| 614 |
|
| 615 |
-
# روش دوم:
|
| 616 |
for attempt in range(10):
|
| 617 |
try:
|
| 618 |
-
if hasattr(client, "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 619 |
await client.send_file(chat_id, abs_path)
|
| 620 |
if caption:
|
| 621 |
await send_with_keyboard(client, chat_id, caption, True)
|
| 622 |
return True
|
| 623 |
-
elif hasattr(client, "send_document"):
|
| 624 |
-
await client.send_document(chat_id, abs_path, caption=caption)
|
| 625 |
-
return True
|
| 626 |
except Exception as e:
|
| 627 |
err_msg = str(e)[:100]
|
| 628 |
error_logs.append(f"Rubpy Send Error: {err_msg}")
|
| 629 |
-
if "502" in err_msg or "timeout" in err_msg.lower() or "time" in err_msg.lower():
|
| 630 |
-
|
| 631 |
-
continue
|
| 632 |
-
else:
|
| 633 |
-
await asyncio.sleep(2)
|
| 634 |
|
| 635 |
return "\n".join(error_logs[-6:])
|
| 636 |
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
]
|
| 641 |
|
| 642 |
SPEAKERS = {
|
| 643 |
"1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
|
|
@@ -653,10 +647,166 @@ SPEAKERS = {
|
|
| 653 |
}
|
| 654 |
|
| 655 |
user_states = {}
|
| 656 |
-
processed_messages_list = user_credits_db.get("system_processed_messages",[])
|
| 657 |
-
processed_message_ids = set(processed_messages_list)
|
| 658 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 659 |
|
|
|
|
|
|
|
|
|
|
| 660 |
async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
|
| 661 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 662 |
creds = get_user_credits(str_chat_id)
|
|
@@ -701,7 +851,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
|
|
| 701 |
history = history[-40:]
|
| 702 |
if history[0]["role"] == "model": history = history[1:]
|
| 703 |
|
| 704 |
-
# --- سیستم پافشاری (تلاش مجدد) برای دریافت جواب از هوش مصنوعی ---
|
| 705 |
final_answer = None
|
| 706 |
for attempt in range(3):
|
| 707 |
keys_to_try = get_next_gemini_keys(100)
|
|
@@ -811,7 +960,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
|
|
| 811 |
await asyncio.sleep(2.5)
|
| 812 |
except Exception: await asyncio.sleep(2.5)
|
| 813 |
|
| 814 |
-
# --- کسر اعتبار فقط در صورتی که حداقل یک بخش از پیام موفقیتآمیز ارسال شده باشد ---
|
| 815 |
if success_sent and not creds.get("is_premium"):
|
| 816 |
user_credits_db[str_chat_id]["chat"] -= 1
|
| 817 |
save_db(user_credits_db)
|
|
@@ -819,7 +967,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
|
|
| 819 |
except Exception:
|
| 820 |
await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
|
| 821 |
|
| 822 |
-
|
| 823 |
async def process_image(client, chat_id, prompt, size_choice="1"):
|
| 824 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 825 |
creds = get_user_credits(str_chat_id)
|
|
@@ -889,7 +1036,6 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
|
|
| 889 |
short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
|
| 890 |
proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
|
| 891 |
|
| 892 |
-
# --- سیستم پافشاری برای ساخت عکس ---
|
| 893 |
generated_image = None
|
| 894 |
last_error_log = "هیچ اتصالی برقرار نشد."
|
| 895 |
|
|
@@ -928,7 +1074,6 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
|
|
| 928 |
await asyncio.sleep(1)
|
| 929 |
caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}"
|
| 930 |
|
| 931 |
-
# آپلود قدرتمند با 3 بار تلاش مجدد بیرونی
|
| 932 |
upload_result = False
|
| 933 |
error_log_img = ""
|
| 934 |
for up_att in range(3):
|
|
@@ -940,7 +1085,6 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
|
|
| 940 |
error_log_img = res
|
| 941 |
await asyncio.sleep(4)
|
| 942 |
|
| 943 |
-
# --- کسر اعتبار فقط در صورت موفقیت کامل آپلود به کاربر ---
|
| 944 |
if upload_result is True:
|
| 945 |
if not creds.get("is_premium"):
|
| 946 |
user_credits_db[str_chat_id]["image"] -= 1
|
|
@@ -952,7 +1096,6 @@ async def process_image(client, chat_id, prompt, size_choice="1"):
|
|
| 952 |
except Exception as e:
|
| 953 |
await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره و ارسال عکس:\n{str(e)[:150]}", True)
|
| 954 |
|
| 955 |
-
|
| 956 |
async def translate_text_aloha(prompt_text):
|
| 957 |
session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
|
| 958 |
join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join"
|
|
@@ -986,7 +1129,6 @@ async def translate_text_aloha(prompt_text):
|
|
| 986 |
|
| 987 |
return prompt_text
|
| 988 |
|
| 989 |
-
|
| 990 |
async def process_image_edit(client, chat_id, image_bytes, prompt):
|
| 991 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 992 |
creds = get_user_credits(str_chat_id)
|
|
@@ -1002,7 +1144,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
|
|
| 1002 |
if not translated_prompt or translated_prompt.strip() == "":
|
| 1003 |
translated_prompt = prompt
|
| 1004 |
|
| 1005 |
-
# --- سیستم پافشاری برای ویرایش عکس ---
|
| 1006 |
generated_image = None
|
| 1007 |
last_error_log = "سرور پاسخ نداد."
|
| 1008 |
|
|
@@ -1051,7 +1192,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
|
|
| 1051 |
error_log_edit = res
|
| 1052 |
await asyncio.sleep(4)
|
| 1053 |
|
| 1054 |
-
# --- کسر اعتبار فقط پس از تحویل موفقیت آمیز ---
|
| 1055 |
if upload_result is True:
|
| 1056 |
if not creds.get("is_premium"):
|
| 1057 |
user_credits_db[str_chat_id]["edit_image"] -= 1
|
|
@@ -1063,7 +1203,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
|
|
| 1063 |
except Exception as e:
|
| 1064 |
await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
|
| 1065 |
|
| 1066 |
-
|
| 1067 |
async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
| 1068 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1069 |
creds = get_user_credits(str_chat_id)
|
|
@@ -1075,7 +1214,6 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
|
| 1075 |
payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
|
| 1076 |
headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
|
| 1077 |
|
| 1078 |
-
# --- سیستم پافشاری برای ساخت صدا ---
|
| 1079 |
audio_bytes = None
|
| 1080 |
last_error = "پاسخی دریافت نشد"
|
| 1081 |
|
|
@@ -1111,11 +1249,9 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
|
| 1111 |
await asyncio.to_thread(sync_write_file, file_name_mp3, audio_bytes)
|
| 1112 |
await asyncio.sleep(1)
|
| 1113 |
|
| 1114 |
-
# ارسال با فرمت Music و مقاومت ۳ برابری
|
| 1115 |
upload_result_file = False
|
| 1116 |
error_log_tts = ""
|
| 1117 |
for up_att in range(3):
|
| 1118 |
-
# 🔴 ارسال متن به صدا بصورت موزیک 🔴
|
| 1119 |
res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
|
| 1120 |
if res is True:
|
| 1121 |
upload_result_file = True
|
|
@@ -1124,7 +1260,6 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
|
| 1124 |
error_log_tts = res
|
| 1125 |
await asyncio.sleep(4)
|
| 1126 |
|
| 1127 |
-
# --- کسر اعتبار فقط پس از تحویل موفق فایل ---
|
| 1128 |
if upload_result_file is True:
|
| 1129 |
if not creds.get("is_premium"):
|
| 1130 |
user_credits_db[str_chat_id]["tts"] -= 1
|
|
@@ -1137,7 +1272,6 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
|
| 1137 |
await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
|
| 1138 |
except Exception: traceback.print_exc()
|
| 1139 |
|
| 1140 |
-
|
| 1141 |
async def process_podcast(client, chat_id, prompt):
|
| 1142 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1143 |
creds = get_user_credits(str_chat_id)
|
|
@@ -1193,7 +1327,6 @@ async def process_podcast(client, chat_id, prompt):
|
|
| 1193 |
payload_gen = {"text": turn["dialogue"], "speaker": turn["speaker_id"], "temperature": 0.9}
|
| 1194 |
chunk_audio_bytes = None
|
| 1195 |
|
| 1196 |
-
# --- پافشاری قدرتمندتر برای دریافت هر بخش پادکست ---
|
| 1197 |
for attempt in range(10):
|
| 1198 |
try:
|
| 1199 |
async with session.post(url_generate, json=payload_gen, timeout=120) as resp:
|
|
@@ -1208,7 +1341,7 @@ async def process_podcast(client, chat_id, prompt):
|
|
| 1208 |
try:
|
| 1209 |
combined_audio = await asyncio.to_thread(sync_combine_audio, combined_audio, chunk_audio_bytes)
|
| 1210 |
except Exception as e:
|
| 1211 |
-
return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا
|
| 1212 |
|
| 1213 |
file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
|
| 1214 |
await asyncio.to_thread(sync_export_audio, combined_audio, file_name_mp3)
|
|
@@ -1222,12 +1355,9 @@ async def process_podcast(client, chat_id, prompt):
|
|
| 1222 |
|
| 1223 |
caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
|
| 1224 |
|
| 1225 |
-
# ⚠️ آپلود بسیار قدرتمند پادکست (ارسال با هویت Music برای جلوگیری از 502)
|
| 1226 |
-
# همراه با 3 مرحله تکرار خارجی، که خود شامل 15 + 10 بار تکرار داخلی است!
|
| 1227 |
upload_result_file = False
|
| 1228 |
error_log_pod = ""
|
| 1229 |
for up_att in range(3):
|
| 1230 |
-
# 🔴 ارسال پادکست بصورت موزیک 🔴
|
| 1231 |
res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", caption_file)
|
| 1232 |
if res is True:
|
| 1233 |
upload_result_file = True
|
|
@@ -1236,7 +1366,6 @@ async def process_podcast(client, chat_id, prompt):
|
|
| 1236 |
error_log_pod = res
|
| 1237 |
await asyncio.sleep(5)
|
| 1238 |
|
| 1239 |
-
# --- کسر اعتبار فقط در صورتی که فایل پادکست با موفقیت در روبیکا آپلود شده باشد ---
|
| 1240 |
if upload_result_file is True:
|
| 1241 |
if not creds.get("is_premium"):
|
| 1242 |
user_credits_db[str_chat_id]["podcast"] -= 1
|
|
@@ -1246,7 +1375,6 @@ async def process_podcast(client, chat_id, prompt):
|
|
| 1246 |
|
| 1247 |
if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
|
| 1248 |
|
| 1249 |
-
|
| 1250 |
async def process_stt(client, chat_id, audio_bytes, file_name):
|
| 1251 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1252 |
creds = get_user_credits(str_chat_id)
|
|
@@ -1262,7 +1390,6 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
|
|
| 1262 |
|
| 1263 |
prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبتهای داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافهای نده."
|
| 1264 |
|
| 1265 |
-
# --- سیستم پافشاری برای تبدیل صدا به متن ---
|
| 1266 |
transcribed_text = None
|
| 1267 |
for attempt in range(5):
|
| 1268 |
keys_to_try = get_next_gemini_keys(100)
|
|
@@ -1289,14 +1416,12 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
|
|
| 1289 |
|
| 1290 |
if transcribed_text:
|
| 1291 |
sent = await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
|
| 1292 |
-
# --- کسر اعتبار فقط اگر پیام با موفقیت در روبیکا ارسال شد ---
|
| 1293 |
if sent and not creds.get("is_premium"):
|
| 1294 |
user_credits_db[str_chat_id]["stt"] -= 1
|
| 1295 |
save_db(user_credits_db)
|
| 1296 |
else:
|
| 1297 |
await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
|
| 1298 |
|
| 1299 |
-
|
| 1300 |
async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
|
| 1301 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1302 |
creds = get_user_credits(str_chat_id)
|
|
@@ -1320,7 +1445,6 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
|
|
| 1320 |
|
| 1321 |
is_image = mime_type.startswith('image/')
|
| 1322 |
|
| 1323 |
-
# --- سیستم پافشاری برای تحلیل فایل ---
|
| 1324 |
final_answer = None
|
| 1325 |
for attempt in range(5):
|
| 1326 |
keys_to_try = get_next_gemini_keys(100)
|
|
@@ -1386,7 +1510,6 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
|
|
| 1386 |
|
| 1387 |
if final_answer:
|
| 1388 |
sent = await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
|
| 1389 |
-
# --- کسر اعتبار فقط پس از ارسال موفقیتآمیز نتیجه ---
|
| 1390 |
if sent and not creds.get("is_premium"):
|
| 1391 |
user_credits_db[str_chat_id]["file"] -= 1
|
| 1392 |
save_db(user_credits_db)
|
|
@@ -1396,7 +1519,6 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
|
|
| 1396 |
else:
|
| 1397 |
await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", True)
|
| 1398 |
|
| 1399 |
-
|
| 1400 |
async def process_create_file(client, chat_id, topic):
|
| 1401 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1402 |
creds = get_user_credits(str_chat_id)
|
|
@@ -1410,7 +1532,6 @@ async def process_create_file(client, chat_id, topic):
|
|
| 1410 |
|
| 1411 |
ai_prompt = f"یک مقاله بسیار جامع، کاملا حرفهای، بسیار طولانی و با جزئیات کامل درباره موضوع زیر به زبان فارسی بنویس. فقط متن مقاله را بده و هیچ توضیح اضافهای نده:\n\nموضوع: {topic}"
|
| 1412 |
|
| 1413 |
-
# --- سیستم پافشاری برای تولید متن مقاله ---
|
| 1414 |
article_text = None
|
| 1415 |
for attempt in range(5):
|
| 1416 |
keys_to_try = get_next_gemini_keys(100)
|
|
@@ -1466,11 +1587,8 @@ async def process_create_file(client, chat_id, topic):
|
|
| 1466 |
converter_url = "https://opera8-texttopdf.hf.space/"
|
| 1467 |
uid = uuid.uuid4().hex
|
| 1468 |
|
| 1469 |
-
# =======================================================================
|
| 1470 |
-
# ---- 1. پردازش و ارسال فایل PDF (دونه دونه و با پافشاری شدید) ----
|
| 1471 |
-
# =======================================================================
|
| 1472 |
pdf_success = False
|
| 1473 |
-
for attempt in range(30):
|
| 1474 |
try:
|
| 1475 |
pdf_bytes = None
|
| 1476 |
async with aiohttp.ClientSession() as session:
|
|
@@ -1500,22 +1618,16 @@ async def process_create_file(client, chat_id, topic):
|
|
| 1500 |
|
| 1501 |
if res_upload is True:
|
| 1502 |
pdf_success = True
|
| 1503 |
-
break
|
| 1504 |
except Exception as e:
|
| 1505 |
print(f"PDF error (attempt {attempt+1}):", e)
|
| 1506 |
|
| 1507 |
-
await asyncio.sleep(4)
|
| 1508 |
|
| 1509 |
-
# =======================================================================
|
| 1510 |
-
# استراحت بین دو فایل برای هضم شدن فایل قبلی توسط سیستم روبیکا
|
| 1511 |
-
# =======================================================================
|
| 1512 |
await asyncio.sleep(3.5)
|
| 1513 |
|
| 1514 |
-
# =======================================================================
|
| 1515 |
-
# ---- 2. پردازش و ارسال فایل Word (دونه دونه و با پافشاری شدید) ----
|
| 1516 |
-
# =======================================================================
|
| 1517 |
docx_success = False
|
| 1518 |
-
for attempt in range(30):
|
| 1519 |
try:
|
| 1520 |
docx_bytes = None
|
| 1521 |
async with aiohttp.ClientSession() as session:
|
|
@@ -1545,11 +1657,11 @@ async def process_create_file(client, chat_id, topic):
|
|
| 1545 |
|
| 1546 |
if res_upload is True:
|
| 1547 |
docx_success = True
|
| 1548 |
-
break
|
| 1549 |
except Exception as e:
|
| 1550 |
print(f"DOCX error (attempt {attempt+1}):", e)
|
| 1551 |
|
| 1552 |
-
await asyncio.sleep(4)
|
| 1553 |
|
| 1554 |
try:
|
| 1555 |
if proc_msg:
|
|
@@ -1558,7 +1670,6 @@ async def process_create_file(client, chat_id, topic):
|
|
| 1558 |
if msg_id: await client.delete_messages(chat_id,[msg_id])
|
| 1559 |
except Exception: pass
|
| 1560 |
|
| 1561 |
-
# --- کسر اعتبار فقط در صورتی که حداقل یکی از فایلها با موفقیت کامل آپلود شده باشد ---
|
| 1562 |
if pdf_success and docx_success:
|
| 1563 |
if not creds.get("is_premium"):
|
| 1564 |
user_credits_db[str_chat_id]["chat"] -= 1
|
|
@@ -1572,7 +1683,9 @@ async def process_create_file(client, chat_id, topic):
|
|
| 1572 |
else:
|
| 1573 |
await send_with_keyboard(client, chat_id, "❌ متأسفانه پس از تلاشهای مکرر، سرور قادر به ساخت و ارسال هیچیک از فایلها نبود و اعتباری از شما کسر نشد.", True)
|
| 1574 |
|
| 1575 |
-
|
|
|
|
|
|
|
| 1576 |
if not bot_token:
|
| 1577 |
print("خطا: توکن ربات روبیکا وارد نشده است!")
|
| 1578 |
else:
|
|
@@ -1580,7 +1693,7 @@ else:
|
|
| 1580 |
|
| 1581 |
@bot.on_update(filters.private)
|
| 1582 |
async def main_handler(client, update):
|
| 1583 |
-
global BOT_GUID
|
| 1584 |
|
| 1585 |
try:
|
| 1586 |
if not BOT_GUID:
|
|
@@ -1607,36 +1720,33 @@ else:
|
|
| 1607 |
if not msg_id and msg_obj:
|
| 1608 |
msg_id = msg_obj.get("message_id") if isinstance(msg_obj, dict) else getattr(msg_obj, "message_id", None)
|
| 1609 |
|
| 1610 |
-
|
| 1611 |
-
|
| 1612 |
-
|
| 1613 |
-
|
| 1614 |
-
|
| 1615 |
-
|
| 1616 |
-
|
| 1617 |
-
|
| 1618 |
-
processed_messages_list = processed_messages_list[-5000:]
|
| 1619 |
-
processed_message_ids.clear()
|
| 1620 |
-
processed_message_ids.update(processed_messages_list)
|
| 1621 |
|
| 1622 |
-
|
| 1623 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1624 |
|
| 1625 |
user_text = getattr(update, "text", "") or getattr(msg_obj, "text", "")
|
| 1626 |
user_text_str = str(user_text).strip() if user_text else ""
|
| 1627 |
user_text_lower = user_text_str.lower()
|
| 1628 |
|
| 1629 |
-
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1630 |
-
|
| 1631 |
-
# بررسی اسپم فقط برای همین کاربر
|
| 1632 |
if is_user_spamming(str_chat_id):
|
| 1633 |
return
|
| 1634 |
|
| 1635 |
if str_chat_id not in user_states:
|
| 1636 |
user_states[str_chat_id] = {"mode": None, "text": "", "history":[], "file_bytes": None, "file_name": None}
|
| 1637 |
|
| 1638 |
-
creds = get_user_credits(str_chat_id)
|
| 1639 |
-
|
| 1640 |
if user_text_lower.startswith(f"{ADMIN_CODE} pro=") or user_text_lower.startswith(f"{ADMIN_CODE}pro="):
|
| 1641 |
parts = user_text_str.split("=", 1)
|
| 1642 |
if len(parts) >= 2:
|
|
@@ -1654,6 +1764,9 @@ else:
|
|
| 1654 |
"tts": 5,
|
| 1655 |
"file": 1,
|
| 1656 |
"stt": 5,
|
|
|
|
|
|
|
|
|
|
| 1657 |
"has_joined": True,
|
| 1658 |
"invited_count": 0,
|
| 1659 |
"used_referral": False,
|
|
@@ -1671,6 +1784,8 @@ else:
|
|
| 1671 |
user_credits_db[target_id]["tts"] = 999999
|
| 1672 |
user_credits_db[target_id]["file"] = 999999
|
| 1673 |
user_credits_db[target_id]["stt"] = 999999
|
|
|
|
|
|
|
| 1674 |
|
| 1675 |
save_db(user_credits_db)
|
| 1676 |
await send_with_keyboard(client, chat_id, f"✅ حساب کاربر `{target_id}` به مدت ۳۰ روز شارژ شد و به پرو ارتقا یافت.", False)
|
|
@@ -1720,6 +1835,8 @@ else:
|
|
| 1720 |
status_text = "🥉 نسخه رایگان (آزمایشی)\n⏳ وضعیت: سهمیه روزانه محدود"
|
| 1721 |
|
| 1722 |
chat_rem = "نامحدود ∞" if is_prem else t_creds.get('chat', 0)
|
|
|
|
|
|
|
| 1723 |
podcast_rem = "نامحدود ∞" if is_prem else t_creds.get('podcast', 0)
|
| 1724 |
tts_rem = "نامحدود ∞" if is_prem else t_creds.get('tts', 0)
|
| 1725 |
file_rem = "نامحدود ∞" if is_prem else t_creds.get('file', 0)
|
|
@@ -1741,6 +1858,8 @@ else:
|
|
| 1741 |
💬 چت: {chat_rem}
|
| 1742 |
🎨 تولید عکس: {image_rem}
|
| 1743 |
🪄 ویرایش عکس: {edit_image_rem}
|
|
|
|
|
|
|
| 1744 |
🎙 پادکست: {podcast_rem}
|
| 1745 |
🗣 متن به صدا: {tts_rem}
|
| 1746 |
📁 تحلیل فایل: {file_rem}
|
|
@@ -1825,6 +1944,8 @@ else:
|
|
| 1825 |
daily_note = "*نکته: سهمیه شما هر روز ساعت ۰۰:۰۰ بامداد به صورت خودکار مجدداً شارژ میگردد.*"
|
| 1826 |
|
| 1827 |
chat_rem = "نامحدود ∞" if is_prem else creds['chat']
|
|
|
|
|
|
|
| 1828 |
podcast_rem = "نامحدود ∞" if is_prem else creds['podcast']
|
| 1829 |
tts_rem = "نامحدود ∞" if is_prem else creds['tts']
|
| 1830 |
file_rem = "نامحدود ∞" if is_prem else creds['file']
|
|
@@ -1845,6 +1966,8 @@ else:
|
|
| 1845 |
- 💬 چت هوشمند: {chat_rem}
|
| 1846 |
- 🎨 تولید تصویر: {image_rem} عدد
|
| 1847 |
- 🪄 ویرایش تصویر: {edit_image_rem} عدد
|
|
|
|
|
|
|
| 1848 |
- 🎙 ساخت پادکست: {podcast_rem}
|
| 1849 |
- 🗣 تبدیل متن به صدا: {tts_rem}
|
| 1850 |
- 📁 تحلیل فایل و سند: {file_rem}
|
|
@@ -1854,9 +1977,6 @@ else:
|
|
| 1854 |
await send_with_keyboard(client, chat_id, account_profile, True)
|
| 1855 |
return
|
| 1856 |
|
| 1857 |
-
# ===============================================
|
| 1858 |
-
# 🎁 سیستم جدید دعوت دوستان (دو سر سود) 🎁
|
| 1859 |
-
# ===============================================
|
| 1860 |
if user_text_str in["/invite", "دعوت دوستان 🎁"]:
|
| 1861 |
invites = creds.get("invited_count", 0)
|
| 1862 |
remains = 10 - (invites % 10)
|
|
@@ -1884,6 +2004,7 @@ else:
|
|
| 1884 |
✨ با این ربات میتونی کارهای زیر رو به راحتی انجام بدی:
|
| 1885 |
💬 چت با پیشرفتهترین هوش مصنوعی
|
| 1886 |
🎨 ساخت و ویرایش حرفهای عکس
|
|
|
|
| 1887 |
🎙 ساخت پادکست اختصاصی
|
| 1888 |
🗣 تبدیل متن به صدا (30 گوینده مختلف)
|
| 1889 |
📝 تبدیل صدا و ویدیو به متن
|
|
@@ -1913,6 +2034,7 @@ else:
|
|
| 1913 |
|
| 1914 |
🎁 **بسته طلایی یکماهه شامل:**
|
| 1915 |
🤖 چت با هوش مصنوعی بصورت نامحدود
|
|
|
|
| 1916 |
🗣 تبدیل متن به صدا بصورت نامحدود با ۳۰ گوینده
|
| 1917 |
🎙 ساخت پادکست بصورت نامحدود
|
| 1918 |
|
|
@@ -1978,6 +2100,23 @@ else:
|
|
| 1978 |
await send_with_keyboard(client, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز . همچنین این قسمت متصل به مدل زبانی است و درخواست هارو قبل از ساخت درک میکنه. میتوانید مقاله کامل یک سایت بفرستید با تبلیغات یا هرچی، هوش مصنوعی متن مقاله رو استخراج و پادکست براتون میسازه . در توضیحات امکان مشخص کردن تعداد گوینده به همراه اسم شون نیز از سمت شما امکان پذیر است.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
|
| 1979 |
return
|
| 1980 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1981 |
if user_text_str in["/file", "تحلیل فایل 📁"]:
|
| 1982 |
user_states[str_chat_id]["mode"] = "file_waiting_for_file"
|
| 1983 |
user_states[str_chat_id]["file_bytes"] = None
|
|
@@ -2001,9 +2140,6 @@ else:
|
|
| 2001 |
elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
|
| 2002 |
return
|
| 2003 |
|
| 2004 |
-
# ===============================================
|
| 2005 |
-
# بخش دریافت کد هدیه 8 رقمی از کاربر
|
| 2006 |
-
# ===============================================
|
| 2007 |
elif current_mode == "waiting_for_referral_code":
|
| 2008 |
if user_text_str:
|
| 2009 |
normalized_code = to_english_digits(user_text_str).strip()
|
|
@@ -2071,9 +2207,6 @@ else:
|
|
| 2071 |
await send_with_keyboard(client, chat_id, "✅ کد هدیه با موفقیت ثبت شد!\n🎁 **10 سهمیه تبدیل رایگان متن به صدا** به حساب شما اضافه گردید.", True)
|
| 2072 |
return
|
| 2073 |
|
| 2074 |
-
# ===============================================
|
| 2075 |
-
# آپدیت جدید: در چت ابتدا فایل را میگیرد و میپرسد چه کار کند
|
| 2076 |
-
# ===============================================
|
| 2077 |
elif current_mode == "chat":
|
| 2078 |
if is_file:
|
| 2079 |
await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
|
|
@@ -2100,9 +2233,6 @@ else:
|
|
| 2100 |
await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
|
| 2101 |
return
|
| 2102 |
|
| 2103 |
-
# ===============================================
|
| 2104 |
-
# دریافت سایز قبل از ساخت عکس
|
| 2105 |
-
# ===============================================
|
| 2106 |
elif current_mode == "image_waiting_for_text":
|
| 2107 |
if user_text_str:
|
| 2108 |
user_states[str_chat_id]["text"] = user_text_str
|
|
@@ -2226,6 +2356,100 @@ else:
|
|
| 2226 |
await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع مقاله خود را به صورت متنی بفرستید.", False)
|
| 2227 |
return
|
| 2228 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2229 |
except Exception: traceback.print_exc()
|
| 2230 |
|
| 2231 |
if __name__ == "__main__":
|
|
@@ -2235,8 +2459,7 @@ if __name__ == "__main__":
|
|
| 2235 |
loop = asyncio.get_event_loop()
|
| 2236 |
loop.set_default_executor(concurrent.futures.ThreadPoolExecutor(max_workers=32))
|
| 2237 |
|
| 2238 |
-
# روشن کردن سیستم آپلود دیتابیس هوشمند
|
| 2239 |
loop.create_task(background_db_uploader())
|
| 2240 |
|
| 2241 |
-
print("ربات آلفا پرو با سیستم اشتراک نامحدود +
|
| 2242 |
bot.run()
|
|
|
|
| 16 |
from flask import Flask
|
| 17 |
from rubpy.bot import BotClient, filters
|
| 18 |
|
|
|
|
| 19 |
from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download
|
| 20 |
from PIL import Image
|
| 21 |
from pydub import AudioSegment
|
| 22 |
|
| 23 |
+
# --- تنظیمات آدرس سرورهای تغییر صدا ---
|
| 24 |
+
VC_BASE_URL = "https://sada8888-sada.hf.space"
|
| 25 |
+
LEGACY_BASE_URL = "https://ezmarynoori-rvc.hf.space"
|
| 26 |
+
|
| 27 |
+
LEGACY_MODELS = {
|
| 28 |
+
"1": {"name": "شادمهر", "url": "https://huggingface.co/amirmatrix/shadmehr/resolve/main/added_IVF722_Flat_nprobe_1_shadmehr_v2.zip?download=true", "gender": "male"},
|
| 29 |
+
"2": {"name": "معین", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Moein.zip?download=true", "gender": "male"},
|
| 30 |
+
"3": {"name": "بیلی آیلیش", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Billie.zip?download=true", "gender": "female"},
|
| 31 |
+
"4": {"name": "محسن چاوشی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/chavoshi250.zip?download=true", "gender": "male"},
|
| 32 |
+
"5": {"name": "سیاوش قمیشی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Ghomayshi250.zip?download=true", "gender": "male"},
|
| 33 |
+
"6": {"name": "یاس", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Yas300.zip?download=true", "gender": "male"},
|
| 34 |
+
"7": {"name": "عادل فردوسیپور", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Adel.zip?download=true", "gender": "male"},
|
| 35 |
+
"8": {"name": "باب اسفنجی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Bab_Asfanj300.zip?download=true", "gender": "male"}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
STANDARD_MODELS = {
|
| 39 |
+
"9": {"name": "علی سورنا", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D9%85%D8%AF%D9%84%20%D8%B5%D8%AF%D8%A7%DB%8C%20%D8%B3%D9%88%D8%B1%D9%86%D8%A7.mp3?download=true"},
|
| 40 |
+
"10": {"name": "رونالدو", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D8%B1%D9%88%D9%86%D8%A7%D9%84%D8%AF%D9%88.wav?download=true"},
|
| 41 |
+
"11": {"name": "مسی", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D8%B5%D8%AF%D8%A7%DB%8C-%D9%85%D8%B3%DB%8C.mp3?download=true"},
|
| 42 |
+
"12": {"name": "مریم", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D8%B5%D8%AF%D8%A7%DB%8C%20%D8%AE%D8%A7%D9%86%D9%85.wav?download=true"}
|
| 43 |
+
}
|
| 44 |
|
| 45 |
+
# --- کد مدیریت ---
|
| 46 |
+
ADMIN_CODE = "3011"
|
| 47 |
BOT_GUID = None
|
| 48 |
|
| 49 |
# =======================================================
|
| 50 |
+
# سیستم ضد اسپم کاربر-محور
|
| 51 |
# =======================================================
|
| 52 |
user_message_times = {}
|
| 53 |
|
| 54 |
def is_user_spamming(chat_id):
|
| 55 |
now = time.time()
|
| 56 |
times = user_message_times.get(chat_id,[])
|
| 57 |
+
times = [t for t in times if now - t < 3.0]
|
|
|
|
| 58 |
times.append(now)
|
| 59 |
user_message_times[chat_id] = times
|
|
|
|
|
|
|
| 60 |
if len(times) > 4:
|
| 61 |
return True
|
| 62 |
return False
|
| 63 |
|
| 64 |
+
# --- سیستم دیتابیس حساب کاربری מתصل به دیتاست هاگینگ فیس ---
|
| 65 |
DB_FILE = "users_db.json"
|
| 66 |
DATASET_REPO = "opera8/Karbaran-rayegan-tedad"
|
| 67 |
HF_TOKEN_DB = os.environ.get("HF_TOKEN")
|
|
|
|
| 88 |
|
| 89 |
def load_db():
|
| 90 |
print("در حال تلاش برای خواندن دیتابیس کاربران از دیتاست هاگینگ فیس...")
|
| 91 |
+
if not HF_TOKEN_DB:
|
| 92 |
+
if os.path.exists(DB_FILE):
|
| 93 |
+
try:
|
| 94 |
+
with open(DB_FILE, "r", encoding="utf-8") as f:
|
| 95 |
+
return json.load(f)
|
| 96 |
+
except Exception:
|
| 97 |
+
pass
|
| 98 |
+
return {}
|
| 99 |
+
|
| 100 |
+
while True:
|
| 101 |
try:
|
| 102 |
file_path = hf_hub_download(
|
| 103 |
repo_id=DATASET_REPO,
|
|
|
|
| 109 |
print("✅ دیتابیس با موفقیت از دیتاست هاگینگ فیس لود شد.")
|
| 110 |
return json.load(f)
|
| 111 |
except Exception as e:
|
| 112 |
+
err_msg = str(e)
|
| 113 |
+
if "EntryNotFoundError" in err_msg or "404" in err_msg:
|
| 114 |
+
print("⚠️ فایل دیتابیس در هاگینگ فیس یافت نشد (ساخت دیتابیس جدید).")
|
| 115 |
+
return {}
|
| 116 |
+
|
| 117 |
+
print(f"⚠️ قطعی در ارتباط با هاگینگ فیس! تلاش مجدد در 5 ثانیه... ({err_msg[:50]})")
|
| 118 |
+
time.sleep(5)
|
|
|
|
|
|
|
| 119 |
|
| 120 |
db_needs_upload = False
|
| 121 |
|
|
|
|
| 124 |
with db_lock:
|
| 125 |
try:
|
| 126 |
with open(DB_FILE, "w", encoding="utf-8") as f:
|
| 127 |
+
json.dump(db_data, f, ensure_ascii=False, separators=(',', ':'))
|
| 128 |
+
db_needs_upload = True
|
| 129 |
except Exception as e:
|
| 130 |
print("خطا در ذخیره دیتابیس:", e)
|
| 131 |
|
|
|
|
| 132 |
async def background_db_uploader():
|
| 133 |
global db_needs_upload
|
| 134 |
while True:
|
| 135 |
+
await asyncio.sleep(300)
|
| 136 |
if db_needs_upload and HF_TOKEN_DB:
|
| 137 |
db_needs_upload = False
|
| 138 |
api = HfApi(token=HF_TOKEN_DB)
|
| 139 |
try:
|
|
|
|
| 140 |
await asyncio.to_thread(
|
| 141 |
api.upload_file,
|
| 142 |
path_or_fileobj=DB_FILE,
|
|
|
|
| 147 |
print("✅ بکاپ دیتابیس در هاگینگ فیس ذخیره شد.")
|
| 148 |
except Exception as e:
|
| 149 |
print("❌ خطا در آپلود دیتابیس به هاگینگ فیس:", str(e)[:100])
|
| 150 |
+
db_needs_upload = True
|
| 151 |
|
| 152 |
user_credits_db = load_db()
|
| 153 |
|
|
|
|
| 156 |
if not user_data.get("referral_code"):
|
| 157 |
while True:
|
| 158 |
new_code = ''.join(random.choices(string.digits, k=8))
|
|
|
|
| 159 |
exists = any(isinstance(u, dict) and u.get("referral_code") == new_code for u in user_credits_db.values())
|
| 160 |
if not exists:
|
| 161 |
user_data["referral_code"] = new_code
|
|
|
|
| 186 |
"tts": 5,
|
| 187 |
"file": 1,
|
| 188 |
"stt": 5,
|
| 189 |
+
"voice_conv": 3,
|
| 190 |
+
"voice_clone": 1,
|
| 191 |
+
"last_msg_id": 0,
|
| 192 |
"has_joined": False,
|
| 193 |
"invited_count": 0,
|
| 194 |
"used_referral": False,
|
|
|
|
| 197 |
save_db(user_credits_db)
|
| 198 |
|
| 199 |
user_data = user_credits_db[str_chat_id]
|
| 200 |
+
|
| 201 |
+
if "voice_conv" not in user_data: user_data["voice_conv"] = 3
|
| 202 |
+
if "voice_clone" not in user_data: user_data["voice_clone"] = 1
|
| 203 |
+
if "last_msg_id" not in user_data: user_data["last_msg_id"] = 0
|
| 204 |
+
|
| 205 |
is_premium = user_data.get("is_premium", False)
|
| 206 |
|
| 207 |
if is_premium and user_data.get("expire_date"):
|
|
|
|
| 224 |
user_data["tts"] = 5
|
| 225 |
user_data["file"] = 1
|
| 226 |
user_data["stt"] = 5
|
| 227 |
+
user_data["voice_conv"] = 3
|
| 228 |
+
user_data["voice_clone"] = 1
|
| 229 |
save_db(user_credits_db)
|
| 230 |
|
| 231 |
return user_data
|
| 232 |
|
| 233 |
def to_english_digits(text):
|
| 234 |
+
if not text: return text
|
|
|
|
| 235 |
persian_digits = '۰۱۲۳۴۵۶۷۸۹'
|
| 236 |
arabic_digits = '٠١٢٣٤٥٦٧٨٩'
|
| 237 |
english_digits = '0123456789'
|
|
|
|
| 243 |
|
| 244 |
@app.route('/')
|
| 245 |
def home():
|
| 246 |
+
return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دعوت دوستان + سیستم تغییر صدا) روشن است! 🚀"
|
| 247 |
|
| 248 |
def run_flask():
|
| 249 |
app.run(host="0.0.0.0", port=7860, threaded=True)
|
| 250 |
|
| 251 |
+
# --- توابع کمکی ---
|
| 252 |
def sync_save_image(image, file_name):
|
| 253 |
rgb_im = image.convert('RGB')
|
| 254 |
rgb_im.save(file_name, format="JPEG", quality=100)
|
|
|
|
| 288 |
{"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا🗣️"}
|
| 289 |
]
|
| 290 |
},
|
| 291 |
+
{
|
| 292 |
+
"buttons":[
|
| 293 |
+
{"id": "vc_btn", "type": "Simple", "button_text": "تغییر صدا 🎙️"},
|
| 294 |
+
{"id": "clone_btn", "type": "Simple", "button_text": "کلون کردن صدا 👤"}
|
| 295 |
+
]
|
| 296 |
+
},
|
| 297 |
{
|
| 298 |
"buttons":[
|
| 299 |
{"id": "stt_btn", "type": "Simple", "button_text": "فایل صوتی به متن 📝"},
|
|
|
|
| 367 |
elif hasattr(res, 'exist') and hasattr(res.exist, 'chat'):
|
| 368 |
CHANNEL_GUID = getattr(res.exist.chat, 'object_guid', None)
|
| 369 |
|
| 370 |
+
if not CHANNEL_GUID: return True
|
|
|
|
| 371 |
|
| 372 |
+
payload = {"channel_guid": CHANNEL_GUID, "member_guid": user_id}
|
|
|
|
|
|
|
|
|
|
| 373 |
res = await client._make_request("getChannelParticipant", payload)
|
| 374 |
|
| 375 |
+
if isinstance(res, dict) and res.get("status") == "OK":
|
| 376 |
+
data = res.get("data", {})
|
| 377 |
+
if data and "participant" in data: return True
|
| 378 |
+
elif hasattr(res, 'status') and getattr(res, 'status') == "OK":
|
| 379 |
+
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
return False
|
| 381 |
+
except Exception: return False
|
| 382 |
|
| 383 |
async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
|
| 384 |
try:
|
| 385 |
+
if not use_keyboard: return await client.send_message(chat_id, text)
|
| 386 |
+
payload = {"chat_id": chat_id, "text": text, "chat_keypad_type": "New", "chat_keypad": MAIN_KEYPAD_DICT}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
return await client._make_request("sendMessage", payload)
|
| 388 |
except Exception:
|
| 389 |
+
try: return await client.send_message(chat_id, text)
|
| 390 |
+
except Exception: return None
|
|
|
|
|
|
|
|
|
|
| 391 |
|
| 392 |
bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
|
| 393 |
|
| 394 |
# ==================================================================
|
| 395 |
+
# تابع دانلود ضد بمب اتم (پافشاری ۳۵ بار)
|
| 396 |
# ==================================================================
|
| 397 |
async def helper_download_file(client, msg_obj):
|
| 398 |
errors =[]
|
| 399 |
file_obj = None
|
| 400 |
file_id = None
|
| 401 |
|
|
|
|
| 402 |
for attr in['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']:
|
| 403 |
val = getattr(msg_obj, attr, None)
|
| 404 |
if val:
|
| 405 |
file_obj = val
|
| 406 |
+
if hasattr(val, 'file_id'): file_id = val.file_id
|
| 407 |
+
elif isinstance(val, dict) and 'file_id' in val: file_id = val['file_id']
|
|
|
|
|
|
|
| 408 |
break
|
| 409 |
|
| 410 |
if not file_obj and hasattr(msg_obj, "file_id"):
|
| 411 |
file_id = msg_obj.file_id
|
| 412 |
file_obj = msg_obj
|
| 413 |
|
| 414 |
+
if not file_id: raise Exception("خطا: هیچ فایلی در پیام یافت نشد.")
|
|
|
|
| 415 |
|
| 416 |
temp_name = f"temp_dl_{uuid.uuid4().hex}.tmp"
|
| 417 |
|
|
|
|
| 418 |
for attempt in range(20):
|
| 419 |
try:
|
| 420 |
url_get_file = f"https://botapi.rubika.ir/v3/{bot_token}/getFile"
|
|
|
|
| 428 |
if res_data.get("status") == "OK" or res_data.get("status_det") == "OK":
|
| 429 |
download_url = res_data.get("data", {}).get("download_url") or res_data.get("data", {}).get("file_url")
|
| 430 |
if download_url:
|
|
|
|
| 431 |
for dl_attempt in range(3):
|
| 432 |
try:
|
| 433 |
async with session.get(download_url, headers=headers, timeout=60) as dl_resp:
|
| 434 |
if dl_resp.status == 200:
|
| 435 |
data = await dl_resp.read()
|
| 436 |
+
if data and len(data) > 0: return data
|
| 437 |
+
else: errors.append(f"DL HTTP {dl_resp.status}")
|
|
|
|
|
|
|
| 438 |
await asyncio.sleep(2)
|
| 439 |
except Exception as dl_err:
|
| 440 |
errors.append(f"DL Error: {str(dl_err)[:30]}")
|
| 441 |
await asyncio.sleep(2)
|
| 442 |
+
else: errors.append("No download URL in response.")
|
| 443 |
+
else: errors.append(f"API Not OK: {res_data.get('status')}")
|
| 444 |
+
elif resp.status in [502, 503, 500]:
|
|
|
|
|
|
|
| 445 |
errors.append(f"GetFile HTTP {resp.status}")
|
| 446 |
+
await asyncio.sleep(3.5)
|
| 447 |
continue
|
| 448 |
else:
|
| 449 |
errors.append(f"GetFile HTTP {resp.status}")
|
|
|
|
| 452 |
errors.append(f"API Error: {str(e)[:50]}")
|
| 453 |
await asyncio.sleep(2)
|
| 454 |
|
|
|
|
| 455 |
if file_obj:
|
| 456 |
for attempt in range(10):
|
| 457 |
try:
|
| 458 |
if hasattr(client, "download"):
|
| 459 |
result = await client.download(file_obj, save_as=temp_name)
|
| 460 |
+
if isinstance(result, bytes) and len(result) > 0: return result
|
|
|
|
| 461 |
if os.path.exists(temp_name):
|
| 462 |
data = await asyncio.to_thread(sync_read_file, temp_name)
|
| 463 |
os.remove(temp_name)
|
| 464 |
+
if data and len(data) > 0: return data
|
|
|
|
| 465 |
except Exception as e:
|
| 466 |
+
errors.append(f"Rubpy Obj Error: {str(e)[:50]}")
|
|
|
|
| 467 |
await asyncio.sleep(3)
|
| 468 |
|
|
|
|
| 469 |
for attempt in range(5):
|
| 470 |
try:
|
| 471 |
if hasattr(client, "download_file"):
|
|
|
|
| 473 |
if os.path.exists(temp_name):
|
| 474 |
data = await asyncio.to_thread(sync_read_file, temp_name)
|
| 475 |
os.remove(temp_name)
|
| 476 |
+
if data and len(data) > 0: return data
|
|
|
|
| 477 |
except Exception as e:
|
| 478 |
errors.append(f"Rubpy FileId Error: {str(e)[:50]}")
|
| 479 |
await asyncio.sleep(3)
|
| 480 |
|
| 481 |
raise Exception(f"سرورهای دانلود روبیکا پس از ۳۵ بار تلاش پاسخ ندادند!\nلاگ خطاها: {str(errors[-5:])}")
|
| 482 |
|
| 483 |
+
async def helper_download_url_to_bytes(url):
|
| 484 |
+
async with aiohttp.ClientSession() as session:
|
| 485 |
+
for _ in range(3):
|
| 486 |
+
try:
|
| 487 |
+
async with session.get(url, timeout=30) as resp:
|
| 488 |
+
if resp.status == 200:
|
| 489 |
+
return await resp.read()
|
| 490 |
+
except Exception:
|
| 491 |
+
await asyncio.sleep(2)
|
| 492 |
+
return None
|
| 493 |
|
| 494 |
+
# ==================================================================
|
| 495 |
+
# توکنها و کلیدها
|
| 496 |
+
# ==================================================================
|
| 497 |
GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "")
|
| 498 |
GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "")
|
| 499 |
|
| 500 |
_raw_keys =[]
|
| 501 |
+
if GEMINI_KEYS_STR1: _raw_keys.extend(GEMINI_KEYS_STR1.split(","))
|
| 502 |
+
if GEMINI_KEYS_STR2: _raw_keys.extend(GEMINI_KEYS_STR2.split(","))
|
|
|
|
|
|
|
| 503 |
|
| 504 |
GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()]))
|
| 505 |
print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.")
|
|
|
|
| 511 |
global current_gemini_key_index
|
| 512 |
with gemini_key_lock:
|
| 513 |
total_keys = len(GEMINI_KEYS)
|
| 514 |
+
if total_keys == 0: return[]
|
|
|
|
|
|
|
| 515 |
actual_count = min(count, total_keys)
|
| 516 |
selected_keys =[]
|
|
|
|
| 517 |
for _ in range(actual_count):
|
| 518 |
selected_keys.append(GEMINI_KEYS[current_gemini_key_index])
|
| 519 |
current_gemini_key_index = (current_gemini_key_index + 1) % total_keys
|
|
|
|
| 520 |
return selected_keys
|
| 521 |
|
| 522 |
HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
|
| 523 |
HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
|
| 524 |
|
|
|
|
| 525 |
# ==================================================================
|
| 526 |
+
# تابع آپلود فایل (قدرتمند و ضدضربه) با حفظ قابلیت ارسال عکس
|
| 527 |
# ==================================================================
|
| 528 |
async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
|
| 529 |
abs_path = os.path.abspath(file_name)
|
| 530 |
error_logs =[]
|
| 531 |
|
| 532 |
+
api_file_type = "Image" if file_type in ["photo", "Image", "image"] else "Voice" if file_type in["voice", "Voice", "audio"] else file_type
|
| 533 |
+
if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'): api_file_type = "Music"
|
| 534 |
+
if api_file_type == "File" and abs_path.lower().endswith('.mp3'): api_file_type = "Music"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
|
|
|
|
| 536 |
for attempt in range(15):
|
| 537 |
try:
|
| 538 |
url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
|
| 539 |
url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
|
| 540 |
|
| 541 |
async with aiohttp.ClientSession() as session:
|
|
|
|
| 542 |
async with session.post(url_request, json={"type": api_file_type}, timeout=30) as resp:
|
| 543 |
if resp.status != 200:
|
| 544 |
error_logs.append(f"Request HTTP {resp.status}")
|
|
|
|
| 546 |
continue
|
| 547 |
|
| 548 |
req_data = await resp.json()
|
|
|
|
| 549 |
if req_data.get("status") == "OK":
|
| 550 |
upload_url = req_data.get("data", {}).get("upload_url")
|
|
|
|
| 551 |
if upload_url:
|
| 552 |
with open(abs_path, "rb") as f:
|
| 553 |
form = aiohttp.FormData()
|
| 554 |
form.add_field('file', f, filename=os.path.basename(abs_path))
|
|
|
|
|
|
|
| 555 |
async with session.post(upload_url, data=form, timeout=300) as up_resp:
|
| 556 |
if up_resp.status != 200:
|
| 557 |
error_logs.append(f"Upload HTTP {up_resp.status}")
|
| 558 |
+
await asyncio.sleep(3) if up_resp.status in[502, 503, 500] else asyncio.sleep(1.5)
|
|
|
|
|
|
|
|
|
|
| 559 |
continue
|
| 560 |
|
| 561 |
+
try: up_data = await up_resp.json()
|
|
|
|
| 562 |
except Exception as json_err:
|
| 563 |
error_logs.append(f"JSON Decode Error: {json_err}")
|
| 564 |
await asyncio.sleep(2)
|
| 565 |
continue
|
| 566 |
|
|
|
|
| 567 |
final_file_id = None
|
| 568 |
if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
|
| 569 |
if "data" in up_data and isinstance(up_data["data"], dict):
|
| 570 |
final_file_id = up_data["data"].get("file_id") or up_data["data"].get("id")
|
| 571 |
+
elif "file_id" in up_data: final_file_id = up_data.get("file_id")
|
|
|
|
| 572 |
|
| 573 |
if final_file_id:
|
| 574 |
send_payload = {
|
|
|
|
| 585 |
continue
|
| 586 |
|
| 587 |
s_data = await send_resp.json()
|
| 588 |
+
if s_data.get("status") == "OK": return True
|
| 589 |
+
else: error_logs.append(f"SendFile API Error: {s_data}")
|
|
|
|
|
|
|
| 590 |
else:
|
| 591 |
if up_data.get("status") == "INVALID_INPUT" and api_file_type == "Voice":
|
| 592 |
api_file_type = "Music"
|
| 593 |
error_logs.append(f"Upload API Error: {up_data}")
|
| 594 |
+
else: error_logs.append(f"Missing upload_url in Response: {req_data}")
|
| 595 |
+
else: error_logs.append(f"Request API Error: {req_data}")
|
|
|
|
|
|
|
| 596 |
except Exception as e:
|
| 597 |
error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
|
| 598 |
await asyncio.sleep(2.5)
|
| 599 |
|
| 600 |
+
# روش دوم: استفاده از متدهای اختصاصی rubpy برای ارسال عکس/فایل (جلوگیری از ارسال عکس به صورت داکیومنت)
|
| 601 |
for attempt in range(10):
|
| 602 |
try:
|
| 603 |
+
if api_file_type == "Image" and hasattr(client, "send_photo"):
|
| 604 |
+
await client.send_photo(chat_id, photo=abs_path, caption=caption)
|
| 605 |
+
return True
|
| 606 |
+
elif api_file_type in ["Voice", "Music"]:
|
| 607 |
+
if hasattr(client, "send_voice"):
|
| 608 |
+
await client.send_voice(chat_id, voice=abs_path, caption=caption)
|
| 609 |
+
return True
|
| 610 |
+
elif hasattr(client, "send_music"):
|
| 611 |
+
await client.send_music(chat_id, music=abs_path, caption=caption)
|
| 612 |
+
return True
|
| 613 |
+
|
| 614 |
+
# در صورتی که هیچکدام از شروط بالا برقرار نبود به عنوان فایل ارسال شود
|
| 615 |
+
if hasattr(client, "send_document"):
|
| 616 |
+
await client.send_document(chat_id, document=abs_path, caption=caption)
|
| 617 |
+
return True
|
| 618 |
+
elif hasattr(client, "send_file"):
|
| 619 |
await client.send_file(chat_id, abs_path)
|
| 620 |
if caption:
|
| 621 |
await send_with_keyboard(client, chat_id, caption, True)
|
| 622 |
return True
|
|
|
|
|
|
|
|
|
|
| 623 |
except Exception as e:
|
| 624 |
err_msg = str(e)[:100]
|
| 625 |
error_logs.append(f"Rubpy Send Error: {err_msg}")
|
| 626 |
+
if "502" in err_msg or "timeout" in err_msg.lower() or "time" in err_msg.lower(): await asyncio.sleep(4)
|
| 627 |
+
else: await asyncio.sleep(2)
|
|
|
|
|
|
|
|
|
|
| 628 |
|
| 629 |
return "\n".join(error_logs[-6:])
|
| 630 |
|
| 631 |
+
# ==================================================================
|
| 632 |
+
# لیستهای اولیه ربات
|
| 633 |
+
# ==================================================================
|
| 634 |
+
WORKER_URLS =["https://opera8-ttspro.hf.space/generate"]
|
| 635 |
|
| 636 |
SPEAKERS = {
|
| 637 |
"1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
|
|
|
|
| 647 |
}
|
| 648 |
|
| 649 |
user_states = {}
|
|
|
|
|
|
|
| 650 |
|
| 651 |
+
# ==================================================================
|
| 652 |
+
# توابع تغییر صدا و کلون کردن
|
| 653 |
+
# ==================================================================
|
| 654 |
+
async def process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, job_type_name, credit_type):
|
| 655 |
+
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 656 |
+
creds = get_user_credits(str_chat_id)
|
| 657 |
+
|
| 658 |
+
proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آمادهسازی فایلها...\n(مدل: {job_type_name})", False)
|
| 659 |
+
|
| 660 |
+
async with aiohttp.ClientSession() as session:
|
| 661 |
+
form = aiohttp.FormData()
|
| 662 |
+
form.add_field('source_audio', src_bytes, filename='src.wav', content_type='audio/wav')
|
| 663 |
+
form.add_field('ref_audio', ref_bytes, filename='ref.wav', content_type='audio/wav')
|
| 664 |
+
|
| 665 |
+
try:
|
| 666 |
+
async with session.post(f"{VC_BASE_URL}/upload", data=form, timeout=43200) as resp:
|
| 667 |
+
if resp.status != 200:
|
| 668 |
+
return await send_with_keyboard(client, chat_id, f"❌ خطا در ارسال فایلها (کد {resp.status})", True)
|
| 669 |
+
data = await resp.json()
|
| 670 |
+
job_id = data.get("job_id")
|
| 671 |
+
total_chunks = data.get("total_chunks", 1)
|
| 672 |
+
chunks = data.get("chunks",[])
|
| 673 |
+
except Exception as e:
|
| 674 |
+
return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور:\n{str(e)[:100]}", True)
|
| 675 |
+
|
| 676 |
+
await send_with_keyboard(client, chat_id, "✅ فایلها ارسال شد. در حال پردازش و تغییر صدا...\n(لطفا چند دقیقه صبور باشید)", False)
|
| 677 |
+
|
| 678 |
+
final_filename = None
|
| 679 |
+
for _ in range(10000):
|
| 680 |
+
await asyncio.sleep(4)
|
| 681 |
+
payload_check = {"job_id": job_id, "total_chunks": total_chunks, "chunks": chunks}
|
| 682 |
+
try:
|
| 683 |
+
async with session.post(f"{VC_BASE_URL}/check_status", json=payload_check, timeout=20) as c_resp:
|
| 684 |
+
if c_resp.status == 200:
|
| 685 |
+
c_data = await c_resp.json()
|
| 686 |
+
if c_data.get("status") == "completed":
|
| 687 |
+
final_filename = c_data.get("filename")
|
| 688 |
+
break
|
| 689 |
+
elif c_data.get("status") in ["failed", "error"]:
|
| 690 |
+
return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش صدا.", True)
|
| 691 |
+
except Exception:
|
| 692 |
+
pass
|
| 693 |
+
|
| 694 |
+
if not final_filename:
|
| 695 |
+
return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True)
|
| 696 |
+
|
| 697 |
+
download_url = f"{VC_BASE_URL}/download/{final_filename}"
|
| 698 |
+
await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
|
| 699 |
+
try:
|
| 700 |
+
async with session.get(download_url, timeout=43200) as d_resp:
|
| 701 |
+
if d_resp.status == 200:
|
| 702 |
+
result_bytes = await d_resp.read()
|
| 703 |
+
else:
|
| 704 |
+
return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
|
| 705 |
+
except Exception:
|
| 706 |
+
return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی.", True)
|
| 707 |
+
|
| 708 |
+
file_name_mp3 = f"vc_standard_{uuid.uuid4().hex[:6]}.mp3"
|
| 709 |
+
await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
|
| 710 |
+
|
| 711 |
+
upload_result = False
|
| 712 |
+
for up_att in range(3):
|
| 713 |
+
res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ {job_type_name} شما آماده است!")
|
| 714 |
+
if res is True:
|
| 715 |
+
upload_result = True
|
| 716 |
+
break
|
| 717 |
+
await asyncio.sleep(4)
|
| 718 |
+
|
| 719 |
+
if upload_result is True:
|
| 720 |
+
if not creds.get("is_premium"):
|
| 721 |
+
user_credits_db[str_chat_id][credit_type] -= 1
|
| 722 |
+
save_db(user_credits_db)
|
| 723 |
+
else:
|
| 724 |
+
await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال در روبیکا فراهم نشد.", True)
|
| 725 |
+
|
| 726 |
+
if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
|
| 727 |
+
|
| 728 |
+
async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, model_name):
|
| 729 |
+
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 730 |
+
creds = get_user_credits(str_chat_id)
|
| 731 |
+
|
| 732 |
+
proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آمادهسازی فایلها...\n(مدل: {model_name})", False)
|
| 733 |
+
|
| 734 |
+
async with aiohttp.ClientSession() as session:
|
| 735 |
+
form = aiohttp.FormData()
|
| 736 |
+
form.add_field('audio_file', src_bytes, filename='input.wav', content_type='audio/wav')
|
| 737 |
+
form.add_field('model_url', model_url)
|
| 738 |
+
form.add_field('pitch', str(pitch))
|
| 739 |
+
form.add_field('algo', 'rmvpe+')
|
| 740 |
+
form.add_field('index_inf', '0.75')
|
| 741 |
+
form.add_field('res_filter', '3')
|
| 742 |
+
form.add_field('env_ratio', '0.25')
|
| 743 |
+
form.add_field('protect', '0.33')
|
| 744 |
+
form.add_field('denoise', 'false')
|
| 745 |
+
form.add_field('reverb', 'false')
|
| 746 |
+
|
| 747 |
+
try:
|
| 748 |
+
async with session.post(f"{LEGACY_BASE_URL}/upload", data=form, timeout=43200) as resp:
|
| 749 |
+
if resp.status != 200:
|
| 750 |
+
return await send_with_keyboard(client, chat_id, f"❌ خطا در ارسال فایلها (کد {resp.status})", True)
|
| 751 |
+
data = await resp.json()
|
| 752 |
+
job_id = data.get("job_id")
|
| 753 |
+
except Exception as e:
|
| 754 |
+
return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور:\n{str(e)[:100]}", True)
|
| 755 |
+
|
| 756 |
+
await send_with_keyboard(client, chat_id, "✅ فایل ارسال شد. در حال پردازش و تغییر صدای شما...\n(لطفا چند دقیقه صبور باشید)", False)
|
| 757 |
+
|
| 758 |
+
final_filename = None
|
| 759 |
+
for _ in range(10000):
|
| 760 |
+
await asyncio.sleep(5)
|
| 761 |
+
try:
|
| 762 |
+
async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=20) as c_resp:
|
| 763 |
+
if c_resp.status == 200:
|
| 764 |
+
c_data = await c_resp.json()
|
| 765 |
+
if c_data.get("status") == "completed":
|
| 766 |
+
final_filename = c_data.get("filename")
|
| 767 |
+
break
|
| 768 |
+
elif c_data.get("status") in["failed", "error", "not_found"]:
|
| 769 |
+
return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش.", True)
|
| 770 |
+
except Exception:
|
| 771 |
+
pass
|
| 772 |
+
|
| 773 |
+
if not final_filename:
|
| 774 |
+
return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True)
|
| 775 |
+
|
| 776 |
+
download_url = f"{LEGACY_BASE_URL}/download/{final_filename}"
|
| 777 |
+
await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
|
| 778 |
+
try:
|
| 779 |
+
async with session.get(download_url, timeout=43200) as d_resp:
|
| 780 |
+
if d_resp.status == 200:
|
| 781 |
+
result_bytes = await d_resp.read()
|
| 782 |
+
else:
|
| 783 |
+
return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
|
| 784 |
+
except Exception:
|
| 785 |
+
return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی.", True)
|
| 786 |
+
|
| 787 |
+
file_name_mp3 = f"vc_legacy_{uuid.uuid4().hex[:6]}.mp3"
|
| 788 |
+
await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
|
| 789 |
+
|
| 790 |
+
upload_result = False
|
| 791 |
+
for up_att in range(3):
|
| 792 |
+
res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ صدای خروجی با مدل {model_name} آماده است!")
|
| 793 |
+
if res is True:
|
| 794 |
+
upload_result = True
|
| 795 |
+
break
|
| 796 |
+
await asyncio.sleep(4)
|
| 797 |
+
|
| 798 |
+
if upload_result is True:
|
| 799 |
+
if not creds.get("is_premium"):
|
| 800 |
+
user_credits_db[str_chat_id]["voice_conv"] -= 1
|
| 801 |
+
save_db(user_credits_db)
|
| 802 |
+
else:
|
| 803 |
+
await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال در روبیکا فراهم نشد.", True)
|
| 804 |
+
|
| 805 |
+
if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
|
| 806 |
|
| 807 |
+
# ==================================================================
|
| 808 |
+
# سایر توابع پردازشی
|
| 809 |
+
# ==================================================================
|
| 810 |
async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
|
| 811 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 812 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 851 |
history = history[-40:]
|
| 852 |
if history[0]["role"] == "model": history = history[1:]
|
| 853 |
|
|
|
|
| 854 |
final_answer = None
|
| 855 |
for attempt in range(3):
|
| 856 |
keys_to_try = get_next_gemini_keys(100)
|
|
|
|
| 960 |
await asyncio.sleep(2.5)
|
| 961 |
except Exception: await asyncio.sleep(2.5)
|
| 962 |
|
|
|
|
| 963 |
if success_sent and not creds.get("is_premium"):
|
| 964 |
user_credits_db[str_chat_id]["chat"] -= 1
|
| 965 |
save_db(user_credits_db)
|
|
|
|
| 967 |
except Exception:
|
| 968 |
await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
|
| 969 |
|
|
|
|
| 970 |
async def process_image(client, chat_id, prompt, size_choice="1"):
|
| 971 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 972 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1036 |
short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
|
| 1037 |
proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
|
| 1038 |
|
|
|
|
| 1039 |
generated_image = None
|
| 1040 |
last_error_log = "هیچ اتصالی برقرار نشد."
|
| 1041 |
|
|
|
|
| 1074 |
await asyncio.sleep(1)
|
| 1075 |
caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}"
|
| 1076 |
|
|
|
|
| 1077 |
upload_result = False
|
| 1078 |
error_log_img = ""
|
| 1079 |
for up_att in range(3):
|
|
|
|
| 1085 |
error_log_img = res
|
| 1086 |
await asyncio.sleep(4)
|
| 1087 |
|
|
|
|
| 1088 |
if upload_result is True:
|
| 1089 |
if not creds.get("is_premium"):
|
| 1090 |
user_credits_db[str_chat_id]["image"] -= 1
|
|
|
|
| 1096 |
except Exception as e:
|
| 1097 |
await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره و ارسال عکس:\n{str(e)[:150]}", True)
|
| 1098 |
|
|
|
|
| 1099 |
async def translate_text_aloha(prompt_text):
|
| 1100 |
session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
|
| 1101 |
join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join"
|
|
|
|
| 1129 |
|
| 1130 |
return prompt_text
|
| 1131 |
|
|
|
|
| 1132 |
async def process_image_edit(client, chat_id, image_bytes, prompt):
|
| 1133 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1134 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1144 |
if not translated_prompt or translated_prompt.strip() == "":
|
| 1145 |
translated_prompt = prompt
|
| 1146 |
|
|
|
|
| 1147 |
generated_image = None
|
| 1148 |
last_error_log = "سرور پاسخ نداد."
|
| 1149 |
|
|
|
|
| 1192 |
error_log_edit = res
|
| 1193 |
await asyncio.sleep(4)
|
| 1194 |
|
|
|
|
| 1195 |
if upload_result is True:
|
| 1196 |
if not creds.get("is_premium"):
|
| 1197 |
user_credits_db[str_chat_id]["edit_image"] -= 1
|
|
|
|
| 1203 |
except Exception as e:
|
| 1204 |
await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
|
| 1205 |
|
|
|
|
| 1206 |
async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
|
| 1207 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1208 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1214 |
payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
|
| 1215 |
headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
|
| 1216 |
|
|
|
|
| 1217 |
audio_bytes = None
|
| 1218 |
last_error = "پاسخی دریافت نشد"
|
| 1219 |
|
|
|
|
| 1249 |
await asyncio.to_thread(sync_write_file, file_name_mp3, audio_bytes)
|
| 1250 |
await asyncio.sleep(1)
|
| 1251 |
|
|
|
|
| 1252 |
upload_result_file = False
|
| 1253 |
error_log_tts = ""
|
| 1254 |
for up_att in range(3):
|
|
|
|
| 1255 |
res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
|
| 1256 |
if res is True:
|
| 1257 |
upload_result_file = True
|
|
|
|
| 1260 |
error_log_tts = res
|
| 1261 |
await asyncio.sleep(4)
|
| 1262 |
|
|
|
|
| 1263 |
if upload_result_file is True:
|
| 1264 |
if not creds.get("is_premium"):
|
| 1265 |
user_credits_db[str_chat_id]["tts"] -= 1
|
|
|
|
| 1272 |
await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
|
| 1273 |
except Exception: traceback.print_exc()
|
| 1274 |
|
|
|
|
| 1275 |
async def process_podcast(client, chat_id, prompt):
|
| 1276 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1277 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1327 |
payload_gen = {"text": turn["dialogue"], "speaker": turn["speaker_id"], "temperature": 0.9}
|
| 1328 |
chunk_audio_bytes = None
|
| 1329 |
|
|
|
|
| 1330 |
for attempt in range(10):
|
| 1331 |
try:
|
| 1332 |
async with session.post(url_generate, json=payload_gen, timeout=120) as resp:
|
|
|
|
| 1341 |
try:
|
| 1342 |
combined_audio = await asyncio.to_thread(sync_combine_audio, combined_audio, chunk_audio_bytes)
|
| 1343 |
except Exception as e:
|
| 1344 |
+
return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا:\n{str(e)}", True)
|
| 1345 |
|
| 1346 |
file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
|
| 1347 |
await asyncio.to_thread(sync_export_audio, combined_audio, file_name_mp3)
|
|
|
|
| 1355 |
|
| 1356 |
caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
|
| 1357 |
|
|
|
|
|
|
|
| 1358 |
upload_result_file = False
|
| 1359 |
error_log_pod = ""
|
| 1360 |
for up_att in range(3):
|
|
|
|
| 1361 |
res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", caption_file)
|
| 1362 |
if res is True:
|
| 1363 |
upload_result_file = True
|
|
|
|
| 1366 |
error_log_pod = res
|
| 1367 |
await asyncio.sleep(5)
|
| 1368 |
|
|
|
|
| 1369 |
if upload_result_file is True:
|
| 1370 |
if not creds.get("is_premium"):
|
| 1371 |
user_credits_db[str_chat_id]["podcast"] -= 1
|
|
|
|
| 1375 |
|
| 1376 |
if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
|
| 1377 |
|
|
|
|
| 1378 |
async def process_stt(client, chat_id, audio_bytes, file_name):
|
| 1379 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1380 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1390 |
|
| 1391 |
prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبتهای داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافهای نده."
|
| 1392 |
|
|
|
|
| 1393 |
transcribed_text = None
|
| 1394 |
for attempt in range(5):
|
| 1395 |
keys_to_try = get_next_gemini_keys(100)
|
|
|
|
| 1416 |
|
| 1417 |
if transcribed_text:
|
| 1418 |
sent = await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
|
|
|
|
| 1419 |
if sent and not creds.get("is_premium"):
|
| 1420 |
user_credits_db[str_chat_id]["stt"] -= 1
|
| 1421 |
save_db(user_credits_db)
|
| 1422 |
else:
|
| 1423 |
await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
|
| 1424 |
|
|
|
|
| 1425 |
async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
|
| 1426 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1427 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1445 |
|
| 1446 |
is_image = mime_type.startswith('image/')
|
| 1447 |
|
|
|
|
| 1448 |
final_answer = None
|
| 1449 |
for attempt in range(5):
|
| 1450 |
keys_to_try = get_next_gemini_keys(100)
|
|
|
|
| 1510 |
|
| 1511 |
if final_answer:
|
| 1512 |
sent = await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
|
|
|
|
| 1513 |
if sent and not creds.get("is_premium"):
|
| 1514 |
user_credits_db[str_chat_id]["file"] -= 1
|
| 1515 |
save_db(user_credits_db)
|
|
|
|
| 1519 |
else:
|
| 1520 |
await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", True)
|
| 1521 |
|
|
|
|
| 1522 |
async def process_create_file(client, chat_id, topic):
|
| 1523 |
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1524 |
creds = get_user_credits(str_chat_id)
|
|
|
|
| 1532 |
|
| 1533 |
ai_prompt = f"یک مقاله بسیار جامع، کاملا حرفهای، بسیار طولانی و با جزئیات کامل درباره موضوع زیر به زبان فارسی بنویس. فقط متن مقاله را بده و هیچ توضیح اضافهای نده:\n\nموضوع: {topic}"
|
| 1534 |
|
|
|
|
| 1535 |
article_text = None
|
| 1536 |
for attempt in range(5):
|
| 1537 |
keys_to_try = get_next_gemini_keys(100)
|
|
|
|
| 1587 |
converter_url = "https://opera8-texttopdf.hf.space/"
|
| 1588 |
uid = uuid.uuid4().hex
|
| 1589 |
|
|
|
|
|
|
|
|
|
|
| 1590 |
pdf_success = False
|
| 1591 |
+
for attempt in range(30):
|
| 1592 |
try:
|
| 1593 |
pdf_bytes = None
|
| 1594 |
async with aiohttp.ClientSession() as session:
|
|
|
|
| 1618 |
|
| 1619 |
if res_upload is True:
|
| 1620 |
pdf_success = True
|
| 1621 |
+
break
|
| 1622 |
except Exception as e:
|
| 1623 |
print(f"PDF error (attempt {attempt+1}):", e)
|
| 1624 |
|
| 1625 |
+
await asyncio.sleep(4)
|
| 1626 |
|
|
|
|
|
|
|
|
|
|
| 1627 |
await asyncio.sleep(3.5)
|
| 1628 |
|
|
|
|
|
|
|
|
|
|
| 1629 |
docx_success = False
|
| 1630 |
+
for attempt in range(30):
|
| 1631 |
try:
|
| 1632 |
docx_bytes = None
|
| 1633 |
async with aiohttp.ClientSession() as session:
|
|
|
|
| 1657 |
|
| 1658 |
if res_upload is True:
|
| 1659 |
docx_success = True
|
| 1660 |
+
break
|
| 1661 |
except Exception as e:
|
| 1662 |
print(f"DOCX error (attempt {attempt+1}):", e)
|
| 1663 |
|
| 1664 |
+
await asyncio.sleep(4)
|
| 1665 |
|
| 1666 |
try:
|
| 1667 |
if proc_msg:
|
|
|
|
| 1670 |
if msg_id: await client.delete_messages(chat_id,[msg_id])
|
| 1671 |
except Exception: pass
|
| 1672 |
|
|
|
|
| 1673 |
if pdf_success and docx_success:
|
| 1674 |
if not creds.get("is_premium"):
|
| 1675 |
user_credits_db[str_chat_id]["chat"] -= 1
|
|
|
|
| 1683 |
else:
|
| 1684 |
await send_with_keyboard(client, chat_id, "❌ متأسفانه پس از تلاشهای مکرر، سرور قادر به ساخت و ارسال هیچیک از فایلها نبود و اعتباری از شما کسر نشد.", True)
|
| 1685 |
|
| 1686 |
+
# ==================================================================
|
| 1687 |
+
# حلقه و مدیریت اصلی ربات
|
| 1688 |
+
# ==================================================================
|
| 1689 |
if not bot_token:
|
| 1690 |
print("خطا: توکن ربات روبیکا وارد نشده است!")
|
| 1691 |
else:
|
|
|
|
| 1693 |
|
| 1694 |
@bot.on_update(filters.private)
|
| 1695 |
async def main_handler(client, update):
|
| 1696 |
+
global BOT_GUID
|
| 1697 |
|
| 1698 |
try:
|
| 1699 |
if not BOT_GUID:
|
|
|
|
| 1720 |
if not msg_id and msg_obj:
|
| 1721 |
msg_id = msg_obj.get("message_id") if isinstance(msg_obj, dict) else getattr(msg_obj, "message_id", None)
|
| 1722 |
|
| 1723 |
+
str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
|
| 1724 |
+
creds = get_user_credits(str_chat_id)
|
| 1725 |
+
|
| 1726 |
+
# --- سیستم فوق بهینه پیگیری پیام (Offset Tracking) ---
|
| 1727 |
+
if msg_id:
|
| 1728 |
+
try:
|
| 1729 |
+
current_msg_int = int(msg_id)
|
| 1730 |
+
last_msg_int = creds.get("last_msg_id", 0)
|
|
|
|
|
|
|
|
|
|
| 1731 |
|
| 1732 |
+
if current_msg_int <= last_msg_int:
|
| 1733 |
+
return
|
| 1734 |
+
|
| 1735 |
+
user_credits_db[str_chat_id]["last_msg_id"] = current_msg_int
|
| 1736 |
+
save_db(user_credits_db)
|
| 1737 |
+
except Exception:
|
| 1738 |
+
pass
|
| 1739 |
|
| 1740 |
user_text = getattr(update, "text", "") or getattr(msg_obj, "text", "")
|
| 1741 |
user_text_str = str(user_text).strip() if user_text else ""
|
| 1742 |
user_text_lower = user_text_str.lower()
|
| 1743 |
|
|
|
|
|
|
|
|
|
|
| 1744 |
if is_user_spamming(str_chat_id):
|
| 1745 |
return
|
| 1746 |
|
| 1747 |
if str_chat_id not in user_states:
|
| 1748 |
user_states[str_chat_id] = {"mode": None, "text": "", "history":[], "file_bytes": None, "file_name": None}
|
| 1749 |
|
|
|
|
|
|
|
| 1750 |
if user_text_lower.startswith(f"{ADMIN_CODE} pro=") or user_text_lower.startswith(f"{ADMIN_CODE}pro="):
|
| 1751 |
parts = user_text_str.split("=", 1)
|
| 1752 |
if len(parts) >= 2:
|
|
|
|
| 1764 |
"tts": 5,
|
| 1765 |
"file": 1,
|
| 1766 |
"stt": 5,
|
| 1767 |
+
"voice_conv": 3,
|
| 1768 |
+
"voice_clone": 1,
|
| 1769 |
+
"last_msg_id": 0,
|
| 1770 |
"has_joined": True,
|
| 1771 |
"invited_count": 0,
|
| 1772 |
"used_referral": False,
|
|
|
|
| 1784 |
user_credits_db[target_id]["tts"] = 999999
|
| 1785 |
user_credits_db[target_id]["file"] = 999999
|
| 1786 |
user_credits_db[target_id]["stt"] = 999999
|
| 1787 |
+
user_credits_db[target_id]["voice_conv"] = 999999
|
| 1788 |
+
user_credits_db[target_id]["voice_clone"] = 999999
|
| 1789 |
|
| 1790 |
save_db(user_credits_db)
|
| 1791 |
await send_with_keyboard(client, chat_id, f"✅ حساب کاربر `{target_id}` به مدت ۳۰ روز شارژ شد و به پرو ارتقا یافت.", False)
|
|
|
|
| 1835 |
status_text = "🥉 نسخه رایگان (آزمایشی)\n⏳ وضعیت: سهمیه روزانه محدود"
|
| 1836 |
|
| 1837 |
chat_rem = "نامحدود ∞" if is_prem else t_creds.get('chat', 0)
|
| 1838 |
+
vc_rem = "نامحدود ∞" if is_prem else t_creds.get('voice_conv', 0)
|
| 1839 |
+
clone_rem = "نامحدود ∞" if is_prem else t_creds.get('voice_clone', 0)
|
| 1840 |
podcast_rem = "نامحدود ∞" if is_prem else t_creds.get('podcast', 0)
|
| 1841 |
tts_rem = "نامحدود ∞" if is_prem else t_creds.get('tts', 0)
|
| 1842 |
file_rem = "نامحدود ∞" if is_prem else t_creds.get('file', 0)
|
|
|
|
| 1858 |
💬 چت: {chat_rem}
|
| 1859 |
🎨 تولید عکس: {image_rem}
|
| 1860 |
🪄 ویرایش عکس: {edit_image_rem}
|
| 1861 |
+
🎙️ تغییر صدا: {vc_rem}
|
| 1862 |
+
👤 کلون کردن صدا: {clone_rem}
|
| 1863 |
🎙 پادکست: {podcast_rem}
|
| 1864 |
🗣 متن به صدا: {tts_rem}
|
| 1865 |
📁 تحلیل فایل: {file_rem}
|
|
|
|
| 1944 |
daily_note = "*نکته: سهمیه شما هر روز ساعت ۰۰:۰۰ بامداد به صورت خودکار مجدداً شارژ میگردد.*"
|
| 1945 |
|
| 1946 |
chat_rem = "نامحدود ∞" if is_prem else creds['chat']
|
| 1947 |
+
vc_rem = "نامحدود ∞" if is_prem else creds.get('voice_conv', 0)
|
| 1948 |
+
clone_rem = "نامحدود ∞" if is_prem else creds.get('voice_clone', 0)
|
| 1949 |
podcast_rem = "نامحدود ∞" if is_prem else creds['podcast']
|
| 1950 |
tts_rem = "نامحدود ∞" if is_prem else creds['tts']
|
| 1951 |
file_rem = "نامحدود ∞" if is_prem else creds['file']
|
|
|
|
| 1966 |
- 💬 چت هوشمند: {chat_rem}
|
| 1967 |
- 🎨 تولید تصویر: {image_rem} عدد
|
| 1968 |
- 🪄 ویرایش تصویر: {edit_image_rem} عدد
|
| 1969 |
+
- 🎙️ تغییر صدا: {vc_rem}
|
| 1970 |
+
- 👤 کلون کردن صدا: {clone_rem}
|
| 1971 |
- 🎙 ساخت پادکست: {podcast_rem}
|
| 1972 |
- 🗣 تبدیل متن به صدا: {tts_rem}
|
| 1973 |
- 📁 تحلیل فایل و سند: {file_rem}
|
|
|
|
| 1977 |
await send_with_keyboard(client, chat_id, account_profile, True)
|
| 1978 |
return
|
| 1979 |
|
|
|
|
|
|
|
|
|
|
| 1980 |
if user_text_str in["/invite", "دعوت دوستان 🎁"]:
|
| 1981 |
invites = creds.get("invited_count", 0)
|
| 1982 |
remains = 10 - (invites % 10)
|
|
|
|
| 2004 |
✨ با این ربات میتونی کارهای زیر رو به راحتی انجام بدی:
|
| 2005 |
💬 چت با پیشرفتهترین هوش مصنوعی
|
| 2006 |
🎨 ساخت و ویرایش حرفهای عکس
|
| 2007 |
+
🎙️ تغییر صدا و کلون کردن صدا
|
| 2008 |
🎙 ساخت پادکست اختصاصی
|
| 2009 |
🗣 تبدیل متن به صدا (30 گوینده مختلف)
|
| 2010 |
📝 تبدیل صدا و ویدیو به متن
|
|
|
|
| 2034 |
|
| 2035 |
🎁 **بسته طلایی یکماهه شامل:**
|
| 2036 |
🤖 چت با هوش مصنوعی بصورت نامحدود
|
| 2037 |
+
🎙️ تغییر صدا و کلون کردن صدای نامحدود
|
| 2038 |
🗣 تبدیل متن به صدا بصورت نامحدود با ۳۰ گوینده
|
| 2039 |
🎙 ساخت پادکست بصورت نامحدود
|
| 2040 |
|
|
|
|
| 2100 |
await send_with_keyboard(client, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز . همچنین این قسمت متصل به مدل زبانی است و درخواست هارو قبل از ساخت درک میکنه. میتوانید مقاله کامل یک سایت بفرستید با تبلیغات یا هرچی، هوش مصنوعی متن مقاله رو استخراج و پادکست براتون میسازه . در توضیحات امکان مشخص کردن تعداد گوینده به همراه اسم شون نیز از سمت شما امکان پذیر است.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
|
| 2101 |
return
|
| 2102 |
|
| 2103 |
+
# ===============================================
|
| 2104 |
+
# بخشهای جدید: تغییر صدا و کلون کردن صدا
|
| 2105 |
+
# ===============================================
|
| 2106 |
+
if user_text_str in["/vc", "تغییر صدا 🎙️"]:
|
| 2107 |
+
user_states[str_chat_id]["mode"] = "vc_waiting_for_voice"
|
| 2108 |
+
user_states[str_chat_id]["file_bytes"] = None
|
| 2109 |
+
await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تغییر صدا** شدید.\n\nلطفاً صدای خود (ویس) را بفرستید تا آن را به صدای شخصیتهای معروف تبدیل کنم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
|
| 2110 |
+
return
|
| 2111 |
+
|
| 2112 |
+
if user_text_str in["/clone", "کلون کردن صدا 👤"]:
|
| 2113 |
+
user_states[str_chat_id]["mode"] = "clone_waiting_for_src"
|
| 2114 |
+
user_states[str_chat_id]["file_bytes"] = None
|
| 2115 |
+
user_states[str_chat_id]["ref_bytes"] = None
|
| 2116 |
+
await send_with_keyboard(client, chat_id, "👤 شما وارد بخش **کلون کردن صدای اختصاصی** شدید.\n\nدر این بخش شما به 2 فایل صوتی نیاز دارید:\n1️⃣ صدای خودتان (ورودی)\n2️⃣ صدای شخص هدف (الگو)\n\nابتدا **صدای خودتان (ورودی)** را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
|
| 2117 |
+
return
|
| 2118 |
+
# ===============================================
|
| 2119 |
+
|
| 2120 |
if user_text_str in["/file", "تحلیل فایل 📁"]:
|
| 2121 |
user_states[str_chat_id]["mode"] = "file_waiting_for_file"
|
| 2122 |
user_states[str_chat_id]["file_bytes"] = None
|
|
|
|
| 2140 |
elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
|
| 2141 |
return
|
| 2142 |
|
|
|
|
|
|
|
|
|
|
| 2143 |
elif current_mode == "waiting_for_referral_code":
|
| 2144 |
if user_text_str:
|
| 2145 |
normalized_code = to_english_digits(user_text_str).strip()
|
|
|
|
| 2207 |
await send_with_keyboard(client, chat_id, "✅ کد هدیه با موفقیت ثبت شد!\n🎁 **10 سهمیه تبدیل رایگان متن به صدا** به حساب شما اضافه گردید.", True)
|
| 2208 |
return
|
| 2209 |
|
|
|
|
|
|
|
|
|
|
| 2210 |
elif current_mode == "chat":
|
| 2211 |
if is_file:
|
| 2212 |
await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
|
|
|
|
| 2233 |
await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
|
| 2234 |
return
|
| 2235 |
|
|
|
|
|
|
|
|
|
|
| 2236 |
elif current_mode == "image_waiting_for_text":
|
| 2237 |
if user_text_str:
|
| 2238 |
user_states[str_chat_id]["text"] = user_text_str
|
|
|
|
| 2356 |
await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع مقاله خود را به صورت متنی بفرستید.", False)
|
| 2357 |
return
|
| 2358 |
|
| 2359 |
+
# ===============================================
|
| 2360 |
+
# بخشهای تغییر صدا و کلون صدا
|
| 2361 |
+
# ===============================================
|
| 2362 |
+
elif current_mode == "vc_waiting_for_voice":
|
| 2363 |
+
if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً یک فایل صوتی یا ویس ارسال کنید.", False)
|
| 2364 |
+
await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل صوتی شما...", False)
|
| 2365 |
+
try:
|
| 2366 |
+
file_bytes = await helper_download_file(client, msg_obj)
|
| 2367 |
+
user_states[str_chat_id]["file_bytes"] = file_bytes
|
| 2368 |
+
user_states[str_chat_id]["mode"] = "vc_waiting_for_model"
|
| 2369 |
+
|
| 2370 |
+
model_menu = "✅ صدای شما دریافت شد.\n\nلطفا **شماره** مدلی که میخواهید صدایتان به آن تبدیل شود را ارسال کنید:\n\n"
|
| 2371 |
+
for k, v in LEGACY_MODELS.items(): model_menu += f"{k}. {v['name']}\n"
|
| 2372 |
+
model_menu += "➖➖➖➖➖➖➖➖\n"
|
| 2373 |
+
for k, v in STANDARD_MODELS.items(): model_menu += f"{k}. {v['name']}\n"
|
| 2374 |
+
|
| 2375 |
+
await send_with_keyboard(client, chat_id, model_menu, False)
|
| 2376 |
+
except Exception as dl_err:
|
| 2377 |
+
await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
|
| 2378 |
+
return
|
| 2379 |
+
|
| 2380 |
+
elif current_mode == "vc_waiting_for_model":
|
| 2381 |
+
choice = to_english_digits(user_text_str).strip()
|
| 2382 |
+
|
| 2383 |
+
if choice in STANDARD_MODELS:
|
| 2384 |
+
if creds["voice_conv"] <= 0: return await send_with_keyboard(client, chat_id, "❌ سهمیه تغییر صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
|
| 2385 |
+
user_states[str_chat_id]["mode"] = None
|
| 2386 |
+
model = STANDARD_MODELS[choice]
|
| 2387 |
+
src_bytes = user_states[str_chat_id]["file_bytes"]
|
| 2388 |
+
await send_with_keyboard(client, chat_id, "📥 در حال آمادهسازی فایلها...", False)
|
| 2389 |
+
ref_bytes = await helper_download_url_to_bytes(model["ref"])
|
| 2390 |
+
if not ref_bytes: return await send_with_keyboard(client, chat_id, "❌ خطا در دسترسی به فایل صدای مدل.", False)
|
| 2391 |
+
|
| 2392 |
+
asyncio.create_task(process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, model["name"], "voice_conv"))
|
| 2393 |
+
|
| 2394 |
+
elif choice in LEGACY_MODELS:
|
| 2395 |
+
if creds["voice_conv"] <= 0: return await send_with_keyboard(client, chat_id, "❌ سهمیه تغییر صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
|
| 2396 |
+
user_states[str_chat_id]["selected_model"] = choice
|
| 2397 |
+
user_states[str_chat_id]["mode"] = "vc_waiting_for_gender"
|
| 2398 |
+
|
| 2399 |
+
gender_msg = f"✅ مدل {LEGACY_MODELS[choice]['name']} انتخاب شد.\n\nبرای تنظیم دقیق فرکانسها به ما بگویید صدایی که خودتان فرستادید صدای یک **مرد** است یا **زن**؟\n\n1. مرد 👨\n2. زن 👩"
|
| 2400 |
+
await send_with_keyboard(client, chat_id, gender_msg, False)
|
| 2401 |
+
else:
|
| 2402 |
+
await send_with_keyboard(client, chat_id, "❌ شماره وارد شده صحیح نیست. لطفاً فقط عدد مدل را بفرستید.", False)
|
| 2403 |
+
return
|
| 2404 |
+
|
| 2405 |
+
elif current_mode == "vc_waiting_for_gender":
|
| 2406 |
+
choice = to_english_digits(user_text_str).strip()
|
| 2407 |
+
if choice not in ["1", "2"]:
|
| 2408 |
+
return await send_with_keyboard(client, chat_id, "❌ لطفاً عدد 1 (مرد) یا 2 (زن) را ارسال کنید.", False)
|
| 2409 |
+
|
| 2410 |
+
user_gender = "male" if choice == "1" else "female"
|
| 2411 |
+
model_key = user_states[str_chat_id]["selected_model"]
|
| 2412 |
+
model = LEGACY_MODELS[model_key]
|
| 2413 |
+
target_gender = model["gender"]
|
| 2414 |
+
|
| 2415 |
+
pitch = 0
|
| 2416 |
+
if target_gender == "female" and user_gender == "male": pitch = 12
|
| 2417 |
+
elif target_gender == "male" and user_gender == "female": pitch = -12
|
| 2418 |
+
|
| 2419 |
+
user_states[str_chat_id]["mode"] = None
|
| 2420 |
+
src_bytes = user_states[str_chat_id]["file_bytes"]
|
| 2421 |
+
asyncio.create_task(process_legacy_vc_job(client, chat_id, src_bytes, model["url"], pitch, model["name"]))
|
| 2422 |
+
return
|
| 2423 |
+
|
| 2424 |
+
elif current_mode == "clone_waiting_for_src":
|
| 2425 |
+
if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً فایل صوتی صدای خودتان را بفرستید.", False)
|
| 2426 |
+
await send_with_keyboard(client, chat_id, "📥 در حال دانلود صدای شما...", False)
|
| 2427 |
+
try:
|
| 2428 |
+
file_bytes = await helper_download_file(client, msg_obj)
|
| 2429 |
+
user_states[str_chat_id]["file_bytes"] = file_bytes
|
| 2430 |
+
user_states[str_chat_id]["mode"] = "clone_waiting_for_ref"
|
| 2431 |
+
await send_with_keyboard(client, chat_id, "✅ صدای شما دریافت شد.\n\nحالا **فایل الگو (صدای شخصی که میخواهید شبیهسازی کنید)** را ارسال کنید.\n(پیشنهاد: فایل بدون نویز و موسیقی، بین ۳ تا ۱۰ ثانیه)", False)
|
| 2432 |
+
except Exception as dl_err:
|
| 2433 |
+
await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
|
| 2434 |
+
return
|
| 2435 |
+
|
| 2436 |
+
elif current_mode == "clone_waiting_for_ref":
|
| 2437 |
+
if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً فایل صوتی الگوی هدف را بفرستید.", False)
|
| 2438 |
+
await send_with_keyboard(client, chat_id, "📥 در حال دانلود صدای الگو...", False)
|
| 2439 |
+
try:
|
| 2440 |
+
ref_bytes = await helper_download_file(client, msg_obj)
|
| 2441 |
+
|
| 2442 |
+
if creds["voice_clone"] <= 0:
|
| 2443 |
+
return await send_with_keyboard(client, chat_id, "❌ سهمیه کلون کردن صدای شما تمام شده است. نیازمند تهیه اشتراک هستید.", False)
|
| 2444 |
+
|
| 2445 |
+
user_states[str_chat_id]["mode"] = None
|
| 2446 |
+
src_bytes = user_states[str_chat_id]["file_bytes"]
|
| 2447 |
+
|
| 2448 |
+
asyncio.create_task(process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, "صدای اختصاصی (کلون شده)", "voice_clone"))
|
| 2449 |
+
except Exception as dl_err:
|
| 2450 |
+
await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
|
| 2451 |
+
return
|
| 2452 |
+
|
| 2453 |
except Exception: traceback.print_exc()
|
| 2454 |
|
| 2455 |
if __name__ == "__main__":
|
|
|
|
| 2459 |
loop = asyncio.get_event_loop()
|
| 2460 |
loop.set_default_executor(concurrent.futures.ThreadPoolExecutor(max_workers=32))
|
| 2461 |
|
|
|
|
| 2462 |
loop.create_task(background_db_uploader())
|
| 2463 |
|
| 2464 |
+
print("ربات آلفا پرو با سیستم اشتراک نامحدود + دانلود پیشرفته + آپدیت دیتابیس (جلوگیری از ریست) + تغییر و کلون صدا روشن شد...")
|
| 2465 |
bot.run()
|