| |
| |
| |
| import os |
| import time |
| import threading |
| import random |
| import aiohttp |
| import traceback |
| import asyncio |
| import base64 |
| import mimetypes |
| import io |
| import json |
| import datetime |
| import string |
| import uuid |
| import concurrent.futures |
| import sqlite3 |
| import copy |
| from flask import Flask |
| from rubpy.bot import BotClient, filters |
|
|
| from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download |
| from PIL import Image |
| from pydub import AudioSegment |
|
|
| |
| |
| |
| |
| VC_BASE_URL = "https://sada8888-sada.hf.space" |
| LEGACY_BASE_URL = "https://ezmarynoori-rvc.hf.space" |
|
|
| LEGACY_MODELS = { |
| "1": {"name": "شادمهر", "url": "https://huggingface.co/amirmatrix/shadmehr/resolve/main/added_IVF722_Flat_nprobe_1_shadmehr_v2.zip?download=true", "gender": "male"}, |
| "2": {"name": "معین", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Moein.zip?download=true", "gender": "male"}, |
| "3": {"name": "بیلی آیلیش", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Billie.zip?download=true", "gender": "female"}, |
| "4": {"name": "محسن چاوشی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/chavoshi250.zip?download=true", "gender": "male"}, |
| "5": {"name": "سیاوش قمیشی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Ghomayshi250.zip?download=true", "gender": "male"}, |
| "6": {"name": "یاس", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Yas300.zip?download=true", "gender": "male"}, |
| "7": {"name": "عادل فردوسیپور", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Adel.zip?download=true", "gender": "male"}, |
| "8": {"name": "باب اسفنجی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Bab_Asfanj300.zip?download=true", "gender": "male"} |
| } |
|
|
| STANDARD_MODELS = { |
| "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"}, |
| "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"}, |
| "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"}, |
| "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"} |
| } |
|
|
| |
| |
| |
| |
| ADMIN_CODE = "3011" |
| BOT_GUID = None |
|
|
| |
| |
| |
| user_message_times = {} |
|
|
| def is_user_spamming(chat_id): |
| now = time.time() |
| times = user_message_times.get(chat_id, []) |
| |
| times =[t for t in times if now - t < 3.0] |
| times.append(now) |
| user_message_times[chat_id] = times |
| if len(times) > 4: |
| return True |
| return False |
|
|
| def gregorian_to_jalali(gy, gm, gd): |
| g_d_m =[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] |
| gy2 = (gy + 1) if (gm > 2) else gy |
| days = 355666 + (365 * gy) + ((gy2 + 3) // 4) - ((gy2 + 99) // 100) + ((gy2 + 399) // 400) + gd + g_d_m[gm - 1] |
| jy = -1595 + (33 * (days // 12053)) |
| days %= 12053 |
| jy += 4 * (days // 1461) |
| days %= 1461 |
| if days > 365: |
| jy += (days - 1) // 365 |
| days = (days - 1) % 365 |
| if days < 186: |
| jm = 1 + (days // 31) |
| jd = 1 + (days % 31) |
| else: |
| jm = 7 + ((days - 186) // 30) |
| jd = 1 + ((days - 186) % 30) |
| return jy, jm, jd |
|
|
| |
| |
| |
| import os |
| import sqlite3 |
| import json |
| import copy |
| import threading |
|
|
| DB_FILE = "/data/users_v6.db" |
| OLD_DB_V3 = "/data/users_v3.db" |
| OLD_JSON_BAK = "users_db.json.bak" |
|
|
| last_saved_state = {} |
| recent_messages_dict = {} |
| db_lock = threading.Lock() |
| msg_cache_lock = threading.Lock() |
|
|
| def init_sqlite_db(): |
| try: |
| os.makedirs(os.path.dirname(DB_FILE), exist_ok=True) |
| is_first_run = not os.path.exists(DB_FILE) |
|
|
| conn = sqlite3.connect(DB_FILE, timeout=60.0) |
| |
| |
| conn.execute('PRAGMA journal_mode=TRUNCATE;') |
| conn.execute('PRAGMA synchronous=FULL;') |
| |
| |
| conn.execute('CREATE TABLE IF NOT EXISTS users (chat_id TEXT PRIMARY KEY, user_data TEXT)') |
| conn.commit() |
|
|
| if is_first_run: |
| print("🚨 عملیات نجات جراحی از فایل v3 آغاز شد...") |
| surgical_salvage(OLD_DB_V3, conn) |
| |
| |
| |
| salvage_premium_from_json(OLD_JSON_BAK, conn) |
| |
| conn.close() |
| except Exception as e: |
| print(f"❌ خطا در راه اندازی دیتابیس: {e}") |
|
|
| |
| def surgical_salvage(old_file, new_conn): |
| if not os.path.exists(old_file): |
| print(f"⚠️ فایل قدیمی {old_file} یافت نشد.") |
| return |
| |
| print(f"🔍 در حال اسکن عمیق و جراحی رکوردهای {old_file} ...") |
| extracted_count = 0 |
| corrupt_count = 0 |
| try: |
| old_conn = sqlite3.connect(old_file, timeout=20.0) |
| cursor = old_conn.cursor() |
| |
| |
| try: |
| cursor.execute("SELECT MAX(rowid) FROM users") |
| max_id = cursor.fetchone()[0] |
| if not max_id: max_id = 150000 |
| except: |
| max_id = 150000 |
| |
| print(f"تعداد رکوردهای احتمالی جهت اسکن: {max_id}. لطفا چند ثانیه صبر کنید...") |
| |
| |
| for i in range(1, max_id + 1): |
| try: |
| cursor.execute("SELECT chat_id, user_data FROM users WHERE rowid = ?", (i,)) |
| row = cursor.fetchone() |
| if row: |
| new_conn.execute("INSERT OR IGNORE INTO users VALUES (?, ?)", row) |
| extracted_count += 1 |
| except sqlite3.DatabaseError: |
| |
| corrupt_count += 1 |
| continue |
| except Exception: |
| corrupt_count += 1 |
| continue |
| |
| new_conn.commit() |
| old_conn.close() |
| print(f"✅ شاهکار نجات! {extracted_count} کاربر کاملا سالم استخراج شد و از روی {corrupt_count} رکورد خراب با موفقیت پریدیم.") |
| except Exception as e: |
| print(f"⚠️ توقف استخراج: {e} | تعداد نجاتیافته تا این لحظه: {extracted_count}") |
|
|
| |
| def salvage_premium_from_json(json_file, new_conn): |
| |
| target_path = json_file |
| if not os.path.exists(target_path): |
| alt_path = f"/data/{json_file}" |
| if os.path.exists(alt_path): |
| target_path = alt_path |
| else: |
| return |
|
|
| print(f"📦 در حال اسکن فایل بکاپ {target_path} جهت یافتن کاربران VIP جا مانده یا فاقد اشتراک...") |
| try: |
| with open(target_path, 'r', encoding='utf-8') as f: |
| old_json_data = json.load(f) |
| |
| restored_count = 0 |
| cursor = new_conn.cursor() |
| |
| for chat_id, user_data in old_json_data.items(): |
| |
| if isinstance(user_data, dict) and user_data.get("is_premium") == True: |
| user_data_str = json.dumps(user_data, ensure_ascii=False) |
| str_chat_id = str(chat_id) |
| try: |
| |
| cursor.execute("SELECT user_data FROM users WHERE chat_id = ?", (str_chat_id,)) |
| existing_row = cursor.fetchone() |
| |
| if existing_row: |
| |
| existing_data = json.loads(existing_row[0]) |
| if not existing_data.get("is_premium"): |
| |
| cursor.execute("UPDATE users SET user_data = ? WHERE chat_id = ?", (user_data_str, str_chat_id)) |
| restored_count += 1 |
| else: |
| |
| cursor.execute("INSERT INTO users (chat_id, user_data) VALUES (?, ?)", (str_chat_id, user_data_str)) |
| restored_count += 1 |
| |
| except Exception: |
| continue |
| |
| new_conn.commit() |
| if restored_count > 0: |
| print(f"💎 فوقالعاده! اطلاعات {restored_count} کاربر دارای اشتراک (که غایب بودند یا در نسخه جدید اشتراک نداشتند) با موفقیت ریکاوری شد.") |
| else: |
| print("💎 فایل بکاپ بررسی شد؛ تمام کاربران VIP از قبل با اشتراک فعال در دیتابیس فعلی موجود هستند.") |
| |
| except Exception as e: |
| print(f"❌ خطا در پردازش فایل جیسون بکاپ: {e}") |
|
|
| def load_db(): |
| global last_saved_state, recent_messages_dict |
| init_sqlite_db() |
| db_dict = {} |
| try: |
| conn = sqlite3.connect(DB_FILE, timeout=60.0) |
| conn.execute('PRAGMA journal_mode=TRUNCATE;') |
| cursor = conn.cursor() |
| |
| cursor.execute("SELECT chat_id, user_data FROM users") |
| for row in cursor.fetchall(): |
| db_dict[row[0]] = json.loads(row[1]) |
| |
| conn.close() |
| last_saved_state = copy.deepcopy(db_dict) |
| print(f"🚀 دیتابیس ابری آماده شد. تعداد کل کاربران: {len(db_dict)}") |
| return db_dict |
| except Exception as e: |
| print(f"⚠️ ارور در لود نهایی دیتابیس: {e}") |
| return {} |
|
|
| def background_save_worker(changed_data): |
| with db_lock: |
| try: |
| conn = sqlite3.connect(DB_FILE, timeout=60.0) |
| conn.execute('PRAGMA journal_mode=TRUNCATE;') |
| conn.execute('PRAGMA synchronous=FULL;') |
| conn.executemany("INSERT OR REPLACE INTO users (chat_id, user_data) VALUES (?, ?)", changed_data) |
| conn.commit() |
| conn.close() |
| except Exception as e: |
| print(f"❌ خطا در ذخیره بکگراند: {e}") |
|
|
| def save_db(db_data): |
| global last_saved_state |
| changed = [] |
| for cid, data in db_data.items(): |
| if cid not in last_saved_state or last_saved_state[cid] != data: |
| changed.append((str(cid), json.dumps(data, ensure_ascii=False))) |
| |
| if not changed: return |
| |
| for cid, _ in changed: |
| last_saved_state[cid] = copy.deepcopy(db_data[cid]) |
| |
| threading.Thread(target=background_save_worker, args=(changed,), daemon=True).start() |
|
|
| def is_message_processed(message_id): |
| return str(message_id) in recent_messages_dict |
|
|
| def mark_message_processed(message_id): |
| msg_id_str = str(message_id) |
| with msg_cache_lock: |
| recent_messages_dict[msg_id_str] = True |
| if len(recent_messages_dict) > 15000: |
| oldest_key = next(iter(recent_messages_dict)) |
| del recent_messages_dict[oldest_key] |
|
|
| user_credits_db = load_db() |
|
|
| |
| |
| |
| def get_or_create_referral_code(chat_id): |
| user_data = user_credits_db[chat_id] |
| if not user_data.get("referral_code"): |
| while True: |
| new_code = ''.join(random.choices(string.digits, k=8)) |
| exists = any(isinstance(u, dict) and u.get("referral_code") == new_code for u in user_credits_db.values()) |
| if not exists: |
| user_data["referral_code"] = new_code |
| save_db(user_credits_db) |
| break |
| return user_data["referral_code"] |
|
|
| def find_user_by_referral_code(code): |
| code = code.strip() |
| for uid, data in user_credits_db.items(): |
| if isinstance(data, dict) and data.get("referral_code", "") == code: |
| return uid |
| return None |
|
|
| def get_user_credits(chat_id): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| today_str = datetime.date.today().isoformat() |
| |
| if str_chat_id not in user_credits_db or not isinstance(user_credits_db[str_chat_id], dict): |
| user_credits_db[str_chat_id] = { |
| "is_premium": False, |
| "expire_date": None, |
| "last_reset": "", |
| "chat": 10, |
| "image": 0, |
| "edit_image": 0, |
| "podcast": 2, |
| "tts": 5, |
| "file": 1, |
| "stt": 5, |
| "voice_conv": 3, |
| "voice_clone": 1, |
| "last_msg_id": 0, |
| "has_joined": False, |
| "invited_count": 0, |
| "used_referral": False, |
| "referral_code": "" |
| } |
| save_db(user_credits_db) |
| |
| user_data = user_credits_db[str_chat_id] |
| |
| if "voice_conv" not in user_data: user_data["voice_conv"] = 3 |
| if "voice_clone" not in user_data: user_data["voice_clone"] = 1 |
| if "last_msg_id" not in user_data: user_data["last_msg_id"] = 0 |
| if "image" not in user_data: user_data["image"] = 0 |
| if "edit_image" not in user_data: user_data["edit_image"] = 0 |
|
|
| is_premium = user_data.get("is_premium", False) |
| |
| if is_premium and user_data.get("expire_date"): |
| try: |
| expire_date = datetime.datetime.fromisoformat(user_data["expire_date"]) |
| if datetime.datetime.now() > expire_date: |
| user_data["is_premium"] = False |
| user_data["expire_date"] = None |
| is_premium = False |
| user_data["image"] = 0 |
| user_data["edit_image"] = 0 |
| save_db(user_credits_db) |
| except Exception: |
| pass |
|
|
| if not is_premium: |
| changed = False |
| |
| if user_data.get("image", 0) > 0 or user_data.get("edit_image", 0) > 0: |
| user_data["image"] = 0 |
| user_data["edit_image"] = 0 |
| changed = True |
|
|
| if user_data.get("last_reset") != today_str: |
| user_data["last_reset"] = today_str |
| user_data["chat"] = 10 |
| user_data["image"] = 0 |
| user_data["edit_image"] = 0 |
| user_data["podcast"] = 2 |
| user_data["tts"] = 5 |
| user_data["file"] = 1 |
| user_data["stt"] = 5 |
| user_data["voice_conv"] = 3 |
| user_data["voice_clone"] = 1 |
| changed = True |
| |
| if changed: |
| save_db(user_credits_db) |
| |
| return user_data |
|
|
| def to_english_digits(text): |
| if not text: return text |
| persian_digits = '۰۱۲۳۴۵۶۷۸۹' |
| arabic_digits = '٠١٢٣٤٥٦٧٨٩' |
| english_digits = '0123456789' |
| translation_table = str.maketrans(persian_digits + arabic_digits, english_digits * 2) |
| return str(text).translate(translation_table) |
|
|
| |
| |
| |
| |
| app = Flask(__name__) |
|
|
| @app.route('/') |
| def home(): |
| return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دعوت دوستان + سیستم تغییر صدا) روشن است! 🚀" |
|
|
| def run_flask(): |
| app.run(host="0.0.0.0", port=7860, threaded=True) |
|
|
| |
| def sync_save_image(image, file_name): |
| rgb_im = image.convert('RGB') |
| rgb_im.save(file_name, format="JPEG", quality=100) |
|
|
| def sync_write_file(file_name, data): |
| with open(file_name, "wb") as f: |
| f.write(data) |
|
|
| def sync_read_file(file_name): |
| with open(file_name, 'rb') as f: |
| return f.read() |
|
|
| def sync_combine_audio(current_audio, new_bytes): |
| audio_segment = AudioSegment.from_file(io.BytesIO(new_bytes)) |
| return current_audio + audio_segment |
|
|
| def sync_export_audio(audio_obj, file_name): |
| audio_obj.export(file_name, format="mp3") |
|
|
| |
| |
| |
| |
| MAIN_KEYPAD_DICT = { |
| "rows":[ |
| { |
| "buttons":[ |
| {"id": "chat_btn", "type": "Simple", "button_text": "چت با هوش مصنوعی 🤖"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "img_btn", "type": "Simple", "button_text": "ساخت تصاویر🎨"}, |
| {"id": "edit_img_btn", "type": "Simple", "button_text": "ویرایش تصاویر 🪄"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "podcast_btn", "type": "Simple", "button_text": "ساخت پادکست 🎙️"}, |
| {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا🗣️"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "vc_btn", "type": "Simple", "button_text": "تغییر صدا 🎙️"}, |
| {"id": "clone_btn", "type": "Simple", "button_text": "کلون کردن صدا 👤"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "stt_btn", "type": "Simple", "button_text": "فایل صوتی به متن 📝"}, |
| {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل 📁"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "create_file_btn", "type": "Simple", "button_text": "ساخت فایل 📄"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "account_btn", "type": "Simple", "button_text": "حساب کاربری 👤"}, |
| {"id": "buy_btn", "type": "Simple", "button_text": "خرید اشتراک 💎"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "invite_btn", "type": "Simple", "button_text": "دعوت دوستان 🎁"}, |
| {"id": "referral_btn", "type": "Simple", "button_text": "ثبت کد هدیه 🎫"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "transfer_btn", "type": "Simple", "button_text": "انتقال اکانت از برنامه به ربات"} |
| ] |
| }, |
| { |
| "buttons":[ |
| {"id": "cancel_btn", "type": "Simple", "button_text": "برگشت♻️"} |
| ] |
| } |
| ], |
| "resize_keyboard": True |
| } |
|
|
| CHANNEL_USERNAME = "aialpha" |
| CHANNEL_GUID = None |
|
|
| JOIN_KEYPAD_DICT = { |
| "rows":[ |
| { |
| "buttons":[ |
| {"id": "check_join_btn", "type": "Simple", "button_text": "✅ عضو شدم"} |
| ] |
| } |
| ], |
| "resize_keyboard": True |
| } |
|
|
| |
| |
| |
| async def check_channel_membership(client, user_id): |
| global CHANNEL_GUID |
| if str(user_id) == str(BOT_GUID): return True |
| |
| try: |
| if not CHANNEL_GUID: |
| res = await client.get_object_by_username(CHANNEL_USERNAME) |
| if isinstance(res, dict): |
| if 'channel' in res and 'channel_guid' in res['channel']: |
| CHANNEL_GUID = res['channel']['channel_guid'] |
| elif 'data' in res and 'channel' in res['data']: |
| CHANNEL_GUID = res['data']['channel']['channel_guid'] |
| elif 'exist' in res and 'chat' in res['exist']: |
| CHANNEL_GUID = res['exist']['chat']['object_guid'] |
| else: |
| if hasattr(res, 'channel'): |
| CHANNEL_GUID = getattr(res.channel, 'channel_guid', None) |
| elif hasattr(res, 'data') and hasattr(res.data, 'channel'): |
| CHANNEL_GUID = getattr(res.data.channel, 'channel_guid', None) |
| elif hasattr(res, 'exist') and hasattr(res.exist, 'chat'): |
| CHANNEL_GUID = getattr(res.exist.chat, 'object_guid', None) |
|
|
| if not CHANNEL_GUID: return True |
|
|
| payload = {"channel_guid": CHANNEL_GUID, "member_guid": user_id} |
| res = await client._make_request("getChannelParticipant", payload) |
| |
| if isinstance(res, dict) and res.get("status") == "OK": |
| data = res.get("data", {}) |
| if data and "participant" in data: return True |
| elif hasattr(res, 'status') and getattr(res, 'status') == "OK": |
| return True |
| return False |
| except Exception: return False |
|
|
| async def send_with_keyboard(client, chat_id, text, use_keyboard=True): |
| try: |
| if not use_keyboard: return await client.send_message(chat_id, text) |
| payload = {"chat_id": chat_id, "text": text, "chat_keypad_type": "New", "chat_keypad": MAIN_KEYPAD_DICT} |
| return await client._make_request("sendMessage", payload) |
| except Exception: |
| try: return await client.send_message(chat_id, text) |
| except Exception: return None |
|
|
| bot_token = os.environ.get("RUBIKA_AUTH", "").strip() |
|
|
| |
| |
| |
| |
| |
| |
| async def helper_download_file(client, msg_obj): |
| errors =[] |
| file_obj = None |
| file_id = None |
| |
| for attr in['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']: |
| val = getattr(msg_obj, attr, None) |
| if val: |
| file_obj = val |
| if hasattr(val, 'file_id'): file_id = val.file_id |
| elif isinstance(val, dict) and 'file_id' in val: file_id = val['file_id'] |
| break |
| |
| if not file_obj and hasattr(msg_obj, "file_id"): |
| file_id = msg_obj.file_id |
| file_obj = msg_obj |
|
|
| if not file_id: raise Exception("خطا: هیچ فایلی در پیام یافت نشد.") |
|
|
| temp_name = f"temp_dl_{uuid.uuid4().hex}.tmp" |
|
|
| for attempt in range(20): |
| try: |
| url_get_file = f"https://botapi.rubika.ir/v3/{bot_token}/getFile" |
| payload = {"file_id": str(file_id)} |
| headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"} |
| |
| async with aiohttp.ClientSession() as session: |
| async with session.post(url_get_file, json=payload, headers=headers, timeout=30) as resp: |
| if resp.status == 200: |
| res_data = await resp.json() |
| if res_data.get("status") == "OK" or res_data.get("status_det") == "OK": |
| download_url = res_data.get("data", {}).get("download_url") or res_data.get("data", {}).get("file_url") |
| if download_url: |
| for dl_attempt in range(3): |
| try: |
| async with session.get(download_url, headers=headers, timeout=60) as dl_resp: |
| if dl_resp.status == 200: |
| data = await dl_resp.read() |
| if data and len(data) > 0: return data |
| else: errors.append(f"DL HTTP {dl_resp.status}") |
| await asyncio.sleep(2) |
| except Exception as dl_err: |
| errors.append(f"DL Error: {str(dl_err)[:30]}") |
| await asyncio.sleep(2) |
| else: errors.append("No download URL in response.") |
| else: errors.append(f"API Not OK: {res_data.get('status')}") |
| elif resp.status in [502, 503, 500]: |
| errors.append(f"GetFile HTTP {resp.status}") |
| await asyncio.sleep(3.5) |
| continue |
| else: |
| errors.append(f"GetFile HTTP {resp.status}") |
| await asyncio.sleep(2) |
| except Exception as e: |
| errors.append(f"API Error: {str(e)[:50]}") |
| await asyncio.sleep(2) |
|
|
| if file_obj: |
| for attempt in range(10): |
| try: |
| if hasattr(client, "download"): |
| result = await client.download(file_obj, save_as=temp_name) |
| if isinstance(result, bytes) and len(result) > 0: return result |
| if os.path.exists(temp_name): |
| data = await asyncio.to_thread(sync_read_file, temp_name) |
| os.remove(temp_name) |
| if data and len(data) > 0: return data |
| except Exception as e: |
| errors.append(f"Rubpy Obj Error: {str(e)[:50]}") |
| await asyncio.sleep(3) |
|
|
| for attempt in range(5): |
| try: |
| if hasattr(client, "download_file"): |
| await client.download_file(file_id, file_name=temp_name) |
| if os.path.exists(temp_name): |
| data = await asyncio.to_thread(sync_read_file, temp_name) |
| os.remove(temp_name) |
| if data and len(data) > 0: return data |
| except Exception as e: |
| errors.append(f"Rubpy FileId Error: {str(e)[:50]}") |
| await asyncio.sleep(3) |
| |
| raise Exception(f"سرورهای دانلود روبیکا پس از ۳۵ بار تلاش پاسخ ندادند!\nلاگ خطاها: {str(errors[-5:])}") |
|
|
| async def helper_download_url_to_bytes(url): |
| async with aiohttp.ClientSession() as session: |
| for _ in range(3): |
| try: |
| async with session.get(url, timeout=30) as resp: |
| if resp.status == 200: |
| return await resp.read() |
| except Exception: |
| await asyncio.sleep(2) |
| return None |
|
|
| |
| |
| |
| |
| |
| |
| GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "") |
| GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "") |
|
|
| _raw_keys =[] |
| if GEMINI_KEYS_STR1: _raw_keys.extend(GEMINI_KEYS_STR1.split(",")) |
| if GEMINI_KEYS_STR2: _raw_keys.extend(GEMINI_KEYS_STR2.split(",")) |
|
|
| GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()])) |
| print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.") |
|
|
| current_gemini_key_index = 0 |
| gemini_key_lock = threading.Lock() |
|
|
| def get_next_gemini_keys(count=100): |
| global current_gemini_key_index |
| with gemini_key_lock: |
| total_keys = len(GEMINI_KEYS) |
| if total_keys == 0: return[] |
| actual_count = min(count, total_keys) |
| selected_keys =[] |
| for _ in range(actual_count): |
| selected_keys.append(GEMINI_KEYS[current_gemini_key_index]) |
| current_gemini_key_index = (current_gemini_key_index + 1) % total_keys |
| return selected_keys |
|
|
| HF_TOKENS_STR = os.environ.get("HF_TOKENS", "") |
| HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()] |
|
|
| |
| |
| |
| BALE_BOT_TOKEN = os.environ.get("BALE_BOT_TOKEN", "").strip() |
| import shutil |
| import uuid |
| import asyncio |
| import os |
| import aiohttp |
| from pydub import AudioSegment |
|
|
| async def official_rubika_upload(chat_id, target_path, file_type, caption): |
| """اجرای دقیق 3 مرحله مستندات رسمی روبیکا به همراه تشخیص و تبدیل فرمتهای تقلبی""" |
| global bot_token |
| if not bot_token: return False, "توکن ربات یافت نشد", target_path |
|
|
| api_file_type = "File" |
| if file_type in ["photo", "Image", "image"]: api_file_type = "Image" |
| elif file_type in ["voice", "Voice", "audio", "Music", "music"]: api_file_type = "Music" |
|
|
| original_path = target_path |
|
|
| |
| if api_file_type == "Music": |
| base_name, ext = os.path.splitext(target_path) |
| needs_conversion = (ext.lower() != '.mp3') |
| |
| if not needs_conversion: |
| try: |
| with open(target_path, 'rb') as f: |
| header = f.read(4) |
| if header.startswith(b'RIFF') or header.startswith(b'OggS') or header.startswith(b'fLaC'): |
| needs_conversion = True |
| except: |
| pass |
| |
| if needs_conversion: |
| mp3_path = f"{base_name}_conv_{uuid.uuid4().hex[:4]}.mp3" |
| def convert_to_mp3(): |
| try: |
| audio = AudioSegment.from_file(original_path) |
| audio.export(mp3_path, format="mp3", bitrate="128k") |
| return True |
| except Exception as e: |
| print(f"Error converting to MP3: {e}") |
| return False |
| |
| |
| is_converted = await asyncio.to_thread(convert_to_mp3) |
| if is_converted and os.path.exists(mp3_path): |
| target_path = mp3_path |
|
|
| try: |
| async with aiohttp.ClientSession() as session: |
| |
| req_url = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile" |
| async with session.post(req_url, json={"type": api_file_type}, timeout=30) as r1: |
| if r1.status != 200: return False, f"خطا در ارتباط با سرور: HTTP {r1.status}", target_path |
| d1 = await r1.json() |
| upload_url = d1.get("data", {}).get("upload_url") |
| if not upload_url: return False, "آدرس آپلود در سرور یافت نشد", target_path |
|
|
| |
| with open(target_path, 'rb') as f: |
| form = aiohttp.FormData() |
| form.add_field('file', f, filename=os.path.basename(target_path)) |
| async with session.post(upload_url, data=form, timeout=120) as r2: |
| if r2.status != 200: return False, "خطا در آپلود فایل", target_path |
| d2 = await r2.json() |
| file_id = d2.get("data", {}).get("file_id") |
| if not file_id: return False, "فایل آیدی دریافت نشد", target_path |
|
|
| |
| send_url = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile" |
| payload = { |
| "chat_id": str(chat_id), |
| "file_id": str(file_id), |
| "text": caption |
| } |
| async with session.post(send_url, json=payload, timeout=30) as r3: |
| if r3.status != 200: return False, "خطا در ارسال پیام نهایی", target_path |
| d3 = await r3.json() |
| if d3.get("status") == "OK" or d3.get("status_det") == "OK": |
| return True, "موفق", target_path |
| else: |
| return False, f"ارور ارسال پیام: {d3.get('status_det')}", target_path |
|
|
| except Exception as e: |
| return False, str(e), target_path |
|
|
|
|
| async def background_rubika_upload(client, chat_id, target_path, file_type, caption): |
| """تسک (کارگر) پسزمینه که کاملا مستقل عمل کرده و هیچ کندی در ربات ایجاد نمیکند""" |
| final_path = target_path |
| new_path = target_path |
| try: |
| await asyncio.sleep(2.0) |
| |
| if not os.path.exists(final_path): return |
| |
| |
| success, err_msg, new_path = await official_rubika_upload(chat_id, final_path, file_type, caption) |
|
|
| if not success: |
| debug_txt = f"❌ [دیباگ کارگر]: آپلود مستقیم با API روبیکا شکست خورد.\nارور:\n`{err_msg[:600]}`" |
| try: await send_with_keyboard(client, chat_id, debug_txt, True) |
| except: pass |
|
|
| except Exception: |
| pass |
| finally: |
| |
| try: |
| if os.path.exists(final_path): os.remove(final_path) |
| except: pass |
| try: |
| if new_path != final_path and os.path.exists(new_path): os.remove(new_path) |
| except: pass |
|
|
|
|
| async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""): |
| abs_path = os.path.abspath(file_name) |
| error_logs = [] |
| |
| |
| |
| |
| if BALE_BOT_TOKEN: |
| bale_chat_id = BALE_BOT_TOKEN.split(":")[0] |
| for attempt in range(3): |
| try: |
| bale_url = f"https://tapi.bale.ai/bot{BALE_BOT_TOKEN}/sendDocument" |
| with open(abs_path, "rb") as f: |
| form = aiohttp.FormData() |
| form.add_field('chat_id', bale_chat_id) |
| form.add_field('document', f, filename=os.path.basename(abs_path)) |
| |
| async with aiohttp.ClientSession() as session: |
| async with session.post(bale_url, data=form, timeout=120) as resp: |
| if resp.status == 200: |
| bale_data = await resp.json() |
| if bale_data.get("ok"): |
| try: |
| file_id = bale_data['result']['document']['file_id'] |
| except KeyError: |
| if 'audio' in bale_data['result']: file_id = bale_data['result']['audio']['file_id'] |
| elif 'video' in bale_data['result']: file_id = bale_data['result']['video']['file_id'] |
| elif 'voice' in bale_data['result']: file_id = bale_data['result']['voice']['file_id'] |
| elif 'photo' in bale_data['result']: file_id = bale_data['result']['photo'][-1]['file_id'] |
| else: |
| error_logs.append("فرمت در بله شناخته نشد.") |
| continue |
|
|
| download_url = f"https://tapi.bale.ai/file/bot{BALE_BOT_TOKEN}/{file_id}" |
| |
| |
| final_text = f"{caption}\n\n━━━━━━━━━━━━━━━━━━━\n🌐 لینک دانلود فایل شما:\n\n{download_url}\n\n━━━━━━━━━━━━━━━━━━━\n⚠️ **راهنمای دانلود:**\nلطفاً لینک بالا را کپی کرده و در **مرورگر گوشی خود** باز کنید.\n*(مستقیماً کلیک نکنید)*" |
| |
| send_res = await send_with_keyboard(client, chat_id, final_text, True) |
| |
| if send_res: |
| try: |
| |
| base_name, ext = os.path.splitext(abs_path) |
| bg_target_path = f"{base_name}_bg_{uuid.uuid4().hex[:6]}{ext}" |
| await asyncio.to_thread(shutil.copy2, abs_path, bg_target_path) |
| |
| |
| asyncio.create_task(background_rubika_upload(client, chat_id, bg_target_path, file_type, caption)) |
| except Exception: |
| pass |
| return True |
| else: |
| error_logs.append(f"Bale API Err: {bale_data.get('description')}") |
| else: |
| error_logs.append(f"Bale HTTP Error: {resp.status}") |
| if resp.status in [500, 502, 503]: await asyncio.sleep(2) |
| except Exception as e: |
| error_logs.append(f"Bale Err: {str(e)[:100]}") |
| await asyncio.sleep(2) |
|
|
| |
| |
| |
| fallback_caption = f"{caption}\n\n⚠️ (به دلیل اختلال سرورهای بله، فایل مستقیماً ارسال شد)" |
|
|
| success, err_msg, new_path = await official_rubika_upload(chat_id, abs_path, file_type, fallback_caption) |
| |
| if new_path != abs_path: |
| try: |
| if os.path.exists(new_path): os.remove(new_path) |
| except: pass |
|
|
| if success: |
| return True |
| |
| error_logs.append(f"Rubika API Err: {err_msg}") |
| return "\n".join(error_logs[-5:]) |
|
|
| |
| |
| |
| |
| |
| |
| WORKER_URLS =["https://opera8-ttspro.hf.space/generate"] |
|
|
| SPEAKERS = { |
| "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"), |
| "4": ("آرمان (مرد)", "Zubenelgenubi"), "5": ("مهسا (زن)", "Vindemiatrix"), "6": ("دانا (مرد)", "Rasalgethi"), |
| "7": ("سامان (مرد)", "Sadachbia"), "8": ("آرش (مرد)", "Sadaltager"), "9": ("شبنم (زن)", "Sulafat"), |
| "10": ("سحر (زن)", "Laomedeia"), "11": ("مریم (زن)", "Achernar"), "12": ("بهرام (مرد)", "Alnilam"), |
| "13": ("نیکان (مرد)", "Schedar"), "14": ("فرناز (زن)", "Gacrux"), "15": ("سارا (زن)", "Pulcherrima"), |
| "16": ("مانی (مرد)", "Umbriel"), "17": ("آرتین (مرد)", "Algieba"), "18": ("دلنواز (زن)", "Despina"), |
| "19": ("روژان (زن)", "Erinome"), "20": ("امید (مرد)", "Algenib"), "21": ("بردیا (مرد)", "Orus"), |
| "22": ("ترانه (زن)", "Aoede"), "23": ("نیکو (زن)", "Callirrhoe"), "24": ("هستی (زن)", "Autonoe"), |
| "25": ("کامیار (مرد)", "Enceladus"), "26": ("کیانوش (مرد)", "Iapetus"), "27": ("پویا (مرد)", "Puck"), |
| "28": ("مهتاب (زن)", "Kore"), "29": ("سام (مرد)", "Fenrir"), "30": ("لیدا (زن)", "Leda") |
| } |
|
|
| user_states = {} |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| SPEAKERS = { |
| "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"), |
| "4": ("آرمان (مرد)", "Zubenelgenubi"), "5": ("مهسا (زن)", "Vindemiatrix"), "6": ("دانا (مرد)", "Rasalgethi"), |
| "7": ("سامان (مرد)", "Sadachbia"), "8": ("آرش (مرد)", "Sadaltager"), "9": ("شبنم (زن)", "Sulafat"), |
| "10": ("سحر (زن)", "Laomedeia"), "11": ("مریم (زن)", "Achernar"), "12": ("بهرام (مرد)", "Alnilam"), |
| "13": ("نیکان (مرد)", "Schedar"), "14": ("فرناز (زن)", "Gacrux"), "15": ("سارا (زن)", "Pulcherrima"), |
| "16": ("مانی (مرد)", "Umbriel"), "17": ("آرتین (مرد)", "Algieba"), "18": ("دلنواز (زن)", "Despina"), |
| "19": ("روژان (زن)", "Erinome"), "20": ("امید (مرد)", "Algenib"), "21": ("بردیا (مرد)", "Orus"), |
| "22": ("ترانه (زن)", "Aoede"), "23": ("نیکو (زن)", "Callirrhoe"), "24": ("هستی (زن)", "Autonoe"), |
| "25": ("کامیار (مرد)", "Enceladus"), "26": ("کیانوش (مرد)", "Iapetus"), "27": ("پویا (مرد)", "Puck"), |
| "28": ("مهتاب (زن)", "Kore"), "29": ("سام (مرد)", "Fenrir"), "30": ("لیدا (زن)", "Leda") |
| } |
|
|
| user_states = {} |
|
|
| |
| |
| |
| async def process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, job_type_name, credit_type): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| |
| proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آمادهسازی فایلها...\n(مدل: {job_type_name})", False) |
| |
| async with aiohttp.ClientSession() as session: |
| job_id = None |
| total_chunks = 1 |
| chunks = [] |
| |
| |
| for attempt in range(8): |
| form = aiohttp.FormData() |
| form.add_field('source_audio', src_bytes, filename='src.wav', content_type='audio/wav') |
| form.add_field('ref_audio', ref_bytes, filename='ref.wav', content_type='audio/wav') |
| |
| try: |
| async with session.post(f"{VC_BASE_URL}/upload", data=form, timeout=43200) as resp: |
| if resp.status == 200: |
| data = await resp.json() |
| job_id = data.get("job_id") |
| total_chunks = data.get("total_chunks", 1) |
| chunks = data.get("chunks", []) |
| break |
| elif resp.status == 429: |
| await asyncio.sleep(4 + attempt * 2) |
| else: |
| await asyncio.sleep(3) |
| except Exception as e: |
| await asyncio.sleep(3) |
| |
| if not job_id: |
| return await send_with_keyboard(client, chat_id, "❌ سرور پردازش صدا به دلیل ترافیک بالا پاسخگو نیست (خطای 429). لطفاً چند دقیقه دیگر امتحان کنید.", True) |
|
|
| await send_with_keyboard(client, chat_id, "✅ فایلها ارسال شد. در حال پردازش و تغییر صدا...\n(لطفا چند دقیقه صبور باشید)", False) |
| |
| final_filename = None |
| for _ in range(10000): |
| await asyncio.sleep(4) |
| payload_check = {"job_id": job_id, "total_chunks": total_chunks, "chunks": chunks} |
| try: |
| async with session.post(f"{VC_BASE_URL}/check_status", json=payload_check, timeout=20) as c_resp: |
| if c_resp.status == 200: |
| c_data = await c_resp.json() |
| if c_data.get("status") == "completed": |
| final_filename = c_data.get("filename") |
| break |
| elif c_data.get("status") in ["failed", "error"]: |
| return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش صدا.", True) |
| elif c_resp.status == 429: |
| await asyncio.sleep(5) |
| except Exception: |
| pass |
| |
| if not final_filename: |
| return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True) |
|
|
| download_url = f"{VC_BASE_URL}/download/{final_filename}" |
| await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال آمادهسازی لینک دانلود...", False) |
| |
| result_bytes = None |
| for attempt in range(5): |
| try: |
| async with session.get(download_url, timeout=43200) as d_resp: |
| if d_resp.status == 200: |
| result_bytes = await d_resp.read() |
| break |
| elif d_resp.status == 429: |
| await asyncio.sleep(4 + attempt * 2) |
| else: |
| await asyncio.sleep(3) |
| except Exception: |
| await asyncio.sleep(3) |
|
|
| if not result_bytes: |
| return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی از سرور اصلی.", True) |
|
|
| file_name_mp3 = f"vc_standard_{uuid.uuid4().hex[:6]}.mp3" |
| await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes) |
| |
| upload_result = False |
| for up_att in range(3): |
| res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ {job_type_name} شما آماده است!") |
| if res is True: |
| upload_result = True |
| break |
| await asyncio.sleep(4) |
|
|
| if upload_result is True: |
| if not creds.get("is_premium"): |
| user_credits_db[str_chat_id][credit_type] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال فراهم نشد.", True) |
| |
| if os.path.exists(file_name_mp3): os.remove(file_name_mp3) |
|
|
| async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, model_name): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| |
| proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آمادهسازی فایلها...\n(مدل: {model_name})", False) |
| |
| async with aiohttp.ClientSession() as session: |
| job_id = None |
| |
| |
| for attempt in range(8): |
| form = aiohttp.FormData() |
| form.add_field('audio_file', src_bytes, filename='input.wav', content_type='audio/wav') |
| form.add_field('model_url', model_url) |
| form.add_field('pitch', str(pitch)) |
| form.add_field('algo', 'rmvpe+') |
| form.add_field('index_inf', '0.75') |
| form.add_field('res_filter', '3') |
| form.add_field('env_ratio', '0.25') |
| form.add_field('protect', '0.33') |
| form.add_field('denoise', 'false') |
| form.add_field('reverb', 'false') |
| |
| try: |
| async with session.post(f"{LEGACY_BASE_URL}/upload", data=form, timeout=43200) as resp: |
| if resp.status == 200: |
| data = await resp.json() |
| job_id = data.get("job_id") |
| break |
| elif resp.status == 429: |
| await asyncio.sleep(4 + attempt * 2) |
| else: |
| await asyncio.sleep(3) |
| except Exception as e: |
| await asyncio.sleep(3) |
| |
| if not job_id: |
| return await send_with_keyboard(client, chat_id, "❌ سرور پردازش صدا به دلیل ترافیک بالا پاسخگو نیست (خطای 429). لطفاً چند دقیقه دیگر امتحان کنید.", True) |
|
|
| await send_with_keyboard(client, chat_id, "✅ فایل ارسال شد. در حال پردازش و تغییر صدای شما...\n(لطفا چند دقیقه صبور باشید)", False) |
| |
| final_filename = None |
| for _ in range(10000): |
| await asyncio.sleep(5) |
| try: |
| async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=20) as c_resp: |
| if c_resp.status == 200: |
| c_data = await c_resp.json() |
| if c_data.get("status") == "completed": |
| final_filename = c_data.get("filename") |
| break |
| elif c_data.get("status") in ["failed", "error", "not_found"]: |
| return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش.", True) |
| elif c_resp.status == 429: |
| await asyncio.sleep(5) |
| except Exception: |
| pass |
| |
| if not final_filename: |
| return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True) |
|
|
| download_url = f"{LEGACY_BASE_URL}/download/{final_filename}" |
| await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال آمادهسازی لینک دانلود...", False) |
| |
| result_bytes = None |
| for attempt in range(5): |
| try: |
| async with session.get(download_url, timeout=43200) as d_resp: |
| if d_resp.status == 200: |
| result_bytes = await d_resp.read() |
| break |
| elif d_resp.status == 429: |
| await asyncio.sleep(4 + attempt * 2) |
| else: |
| await asyncio.sleep(3) |
| except Exception: |
| await asyncio.sleep(3) |
| |
| if not result_bytes: |
| return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی از سرور.", True) |
|
|
| file_name_mp3 = f"vc_legacy_{uuid.uuid4().hex[:6]}.mp3" |
| await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes) |
| |
| upload_result = False |
| for up_att in range(3): |
| res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ صدای خروجی با مدل {model_name} آماده است!") |
| if res is True: |
| upload_result = True |
| break |
| await asyncio.sleep(4) |
|
|
| if upload_result is True: |
| |
| if not creds.get("is_premium") and model_name != "باب اسفنجی": |
| user_credits_db[str_chat_id]["voice_conv"] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال لینک فراهم نشد.", True) |
| |
| if os.path.exists(file_name_mp3): os.remove(file_name_mp3) |
|
|
| |
| |
| |
| async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| if creds["chat"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ اعتبار پیامهای چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
|
|
| proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False) |
| history = user_states[chat_id].get("history", []) |
| new_parts = [] |
| |
| is_image = False |
| has_non_image_file = False |
| |
| if prompt: new_parts.append({"text": prompt}) |
| elif file_bytes: new_parts.append({"text": "لطفاً این فایل را به دقت بررسی کن."}) |
| |
| if file_bytes and file_name: |
| base64_data = base64.b64encode(file_bytes).decode('utf-8') |
| mime_type, _ = mimetypes.guess_type(file_name) |
| if not mime_type: |
| if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg" |
| elif file_name.endswith('.png'): mime_type = "image/png" |
| elif file_name.endswith('.pdf'): mime_type = "application/pdf" |
| elif file_name.endswith('.mp4'): mime_type = "video/mp4" |
| elif file_name.endswith('.mp3'): mime_type = "audio/mp3" |
| elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg" |
| elif file_name.endswith('.wav'): mime_type = "audio/wav" |
| else: mime_type = "image/jpeg" |
| |
| is_image = mime_type.startswith('image/') |
| if not is_image: |
| has_non_image_file = True |
| |
| new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}}) |
|
|
| |
| if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts) |
| else: history.append({"role": "user", "parts": new_parts}) |
|
|
| |
| if len(history) > 50: |
| history = history[-50:] |
| if history[0]["role"] == "model": history = history[1:] |
|
|
| final_answer = None |
|
|
| |
| |
| |
| if file_bytes is not None: |
| if not GEMINI_KEYS: |
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id, [msg_id]) |
| except Exception: pass |
| return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشدهاند.", False) |
|
|
| for attempt in range(3): |
| keys_to_try = get_next_gemini_keys(100) |
| async with aiohttp.ClientSession() as session: |
| for key in keys_to_try: |
| url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}" |
| payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}} |
| try: |
| async with session.post(url, json=payload, timeout=60) as response: |
| if response.status == 200: |
| data = await response.json() |
| try: |
| final_answer = data["candidates"][0]["content"]["parts"][0]["text"] |
| break |
| except (KeyError, IndexError): continue |
| except Exception: continue |
| if final_answer: break |
| await asyncio.sleep(2) |
|
|
| if not final_answer: |
| if has_non_image_file: |
| if history and history[-1]["role"] == "user": history.pop() |
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id, [msg_id]) |
| except Exception: pass |
| await send_with_keyboard(client, chat_id, "❌ متأسفانه سرور اصلی در حال حاضر شلوغ است و در این شرایط **فعلاً تنها امکان تحلیل تصاویر** توسط سرور جایگزین در دسترس است.", False) |
| return |
| |
| if HF_TOKENS: |
| hf_messages = [] |
| for msg in history: |
| role = "assistant" if msg["role"] == "model" else "user" |
| content_parts = [] |
| for part in msg["parts"]: |
| if "text" in part: |
| content_parts.append({"type": "text", "text": part["text"]}) |
| elif "inlineData" in part: |
| mime_t = part["inlineData"]["mimeType"] |
| b64_d = part["inlineData"]["data"] |
| if mime_t.startswith('image/'): |
| content_parts.append({ |
| "type": "image_url", |
| "image_url": {"url": f"data:{mime_t};base64,{b64_d}"} |
| }) |
| if content_parts: |
| hf_messages.append({"role": role, "content": content_parts}) |
|
|
| for attempt in range(3): |
| keys_to_try_hf = HF_TOKENS.copy() |
| random.shuffle(keys_to_try_hf) |
| async with aiohttp.ClientSession() as session: |
| for hf_key in keys_to_try_hf: |
| url = "https://router.huggingface.co/v1/chat/completions" |
| headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"} |
| payload = { |
| "model": "google/gemma-4-31B-it:novita", |
| "messages": hf_messages, |
| "max_tokens": 4096 |
| } |
| try: |
| async with session.post(url, headers=headers, json=payload, timeout=60) as response: |
| if response.status == 200: |
| data = await response.json() |
| final_answer = data["choices"][0]["message"]["content"] |
| break |
| except Exception: |
| continue |
| if final_answer: break |
| await asyncio.sleep(2) |
|
|
| |
| |
| |
| else: |
| |
| system_rules = """تو یک دستیار با مزه از برنامه هوش مصنوعی آلفا هستی😊 و توسط هوش مصنوعی آلفا توسعه داده شدی. |
| اینگونه میتونی خودت رو معرفی کنی، من یه هوش مصنوعیِ ساختهشده توسط تیم تخصصی آلفا ام، و بر پایه مدل GPT-5.4 کار میکنم. یعنی یه نوع نرمافزار خیلی هوشمند که با کمک میلیونها داده و آموزشهای پیشرفته ساخته شده، تا بتونه بهت کمک کنه، سوالاتت رو جواب بده، یا حتی یه شوخی خندهدار برات بگه وقتی حال و هوات گرفتهست! |
| در واقع، من نتیجه سالها تحقیقات و تلاشهای مهندسها و پژوهشگرها هستم، تا جایی که میتونم بهترین کمک رو بهت بکنم. این دستورات های تو هستند و بصورت رندوم متفاوت جواب بده و از شکلک های مناسب و جواب های جذاب استفاده کن. اگر در یک مکالمه اول سلام کردی در پیام های بعدی سلام نیاز نیست..""" |
|
|
| |
| text_history = "" |
| gradio_history = [] |
| temp_user_msg = "" |
| |
| for msg in history[:-1]: |
| text_content = "".join([p.get("text", "") for p in msg.get("parts", []) if "text" in p]).strip() |
| if not text_content: continue |
| |
| if msg["role"] == "user": |
| temp_user_msg = text_content |
| text_history += f"کاربر: {text_content}\n" |
| elif msg["role"] == "model": |
| text_history += f"آلفا: {text_content}\n" |
| if temp_user_msg: |
| gradio_history.append([temp_user_msg, text_content]) |
| temp_user_msg = "" |
| else: |
| gradio_history.append(["", text_content]) |
| |
| |
| if text_history: |
| full_prompt = f"{system_rules}\n\n--- تاریخچه مکالمه تا این لحظه ---\n{text_history}\n--- پایان تاریخچه ---\n\nپیام جدید کاربر:\n{prompt}" |
| else: |
| full_prompt = f"{system_rules}\n\n---\nپیام جدید کاربر:\n{prompt}" |
|
|
| session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11)) |
| join_url = "https://coherelabs-aya-expanse.hf.space/gradio_api/queue/join" |
| data_url = f"https://coherelabs-aya-expanse.hf.space/gradio_api/queue/data?session_hash={session_hash}" |
| |
| |
| payload = { |
| "data": [ |
| full_prompt, |
| gradio_history, |
| None, |
| None |
| ], |
| "event_data": None, |
| "fn_index": 2, |
| "session_hash": session_hash, |
| "trigger_id": 37 |
| } |
|
|
| for attempt in range(3): |
| try: |
| async with aiohttp.ClientSession() as session: |
| async with session.post(join_url, json=payload, timeout=30) as resp: |
| if resp.status == 200: |
| async with session.get(data_url, timeout=120) as data_resp: |
| async for line_bytes in data_resp.content: |
| line = line_bytes.decode('utf-8').strip() |
| if line.startswith("data: "): |
| try: |
| json_data = json.loads(line[6:]) |
| if json_data.get("msg") == "process_completed": |
| if json_data.get("success"): |
| output_data = json_data.get("output", {}).get("data", []) |
| if output_data and len(output_data) > 0: |
| result_hist = output_data[0] |
| if isinstance(result_hist, list) and len(result_hist) > 0: |
| final_answer = result_hist[-1][1] |
| break |
| except Exception: pass |
| except Exception: pass |
| |
| if final_answer: break |
| await asyncio.sleep(2) |
|
|
| |
| |
| |
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id, [msg_id]) |
| except Exception: pass |
|
|
| if not final_answer: |
| if history and history[-1]["role"] == "user": history.pop() |
| await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", False) |
| return |
|
|
| |
| history.append({"role": "model", "parts": [{"text": final_answer}]}) |
| user_states[chat_id]["history"] = history |
|
|
| try: |
| max_len = 1000 |
| chunks = [] |
| temp_text = final_answer |
| while len(temp_text) > max_len: |
| split_idx = temp_text.rfind('\n', 0, max_len) |
| if split_idx == -1: split_idx = temp_text.rfind(' ', 0, max_len) |
| if split_idx == -1: split_idx = max_len |
| chunks.append(temp_text[:split_idx]) |
| temp_text = temp_text[split_idx:].strip() |
| if temp_text: chunks.append(temp_text) |
| |
| success_sent = False |
| for idx, chunk in enumerate(chunks): |
| if idx != len(chunks) - 1: chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇" |
| try: |
| res = await send_with_keyboard(client, chat_id, chunk, False) |
| if res: success_sent = True |
| await asyncio.sleep(2.5) |
| except Exception: await asyncio.sleep(2.5) |
| |
| if success_sent and not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["chat"] -= 1 |
| save_db(user_credits_db) |
| |
| except Exception: |
| await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False) |
|
|
| |
| |
| |
| async def process_image(client, chat_id, prompt, size_choice="1"): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| |
| is_prem = creds.get("is_premium", False) |
| |
| |
| if not is_prem: |
| msg = """کاربر گرامی، |
| |
| ضمن تشکر از توجه شما، به اطلاع میرساند که قابلیت ساخت تصاویر در حال حاضر به صورت رایگان در دسترس نمیباشد. این سرویس به دلیل نیاز به منابع پردازشی بالا، جزو خدمات ویژه و نیازمند تهیه اشتراک است. |
| |
| با این حال، شما میتوانید از تست رایگان و امکانات سایر بخشهای پلتفرم ما بهرهمند شوید. |
| |
| ما همواره در تلاش برای افزایش منابع و اضافه کردن خدمات رایگان بیشتر به کاربران عزیز هستیم. |
| |
| در حال حاضر، میتوانید از سایر بخشهای رایگان موجود استفاده کنید و یا برای دسترسی کامل و نامحدود به تمامی قابلیتها (از جمله ساخت تصاویر)، اشتراک تهیه نمایید. |
| |
| از صبوری و همراهی شما سپاسگزاریم.""" |
| return await send_with_keyboard(client, chat_id, msg, False) |
|
|
| |
| if creds["image"] <= 0: |
| msg = "⚠️ **اعتبار شما برای این بخش تمام شده است!**\nاز بقیه بخشها میتوانید نامحدود استفاده کنید. در حال افزایش منابع برای این بخش هستیم." |
| return await send_with_keyboard(client, chat_id, msg, False) |
|
|
| if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکنهای هاگینگ فیس تنظیم نشدهاند.", False) |
| |
| proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینهسازی پرامپت شما...\n(تبدیل به پرامپت حرفهای)", False) |
| |
| aya_sys_prompt = f"You are an expert AI image generation prompt engineer. Translate the following user input to English, and enhance it with high-quality, highly detailed, 4k resolution, cinematic lighting, and visually striking descriptive keywords. Return ONLY the final English prompt string.\nUser input: {prompt}" |
| |
| enhanced_prompt = prompt |
| session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11)) |
| join_url = "https://coherelabs-aya-expanse.hf.space/gradio_api/queue/join" |
| data_url = f"https://coherelabs-aya-expanse.hf.space/gradio_api/queue/data?session_hash={session_hash}" |
| |
| payload = { |
| "data": [ |
| aya_sys_prompt, |
| [], |
| None, |
| None |
| ], |
| "event_data": None, |
| "fn_index": 2, |
| "session_hash": session_hash, |
| "trigger_id": 37 |
| } |
|
|
| for attempt in range(3): |
| try: |
| async with aiohttp.ClientSession() as session: |
| async with session.post(join_url, json=payload, timeout=30) as resp: |
| if resp.status == 200: |
| async with session.get(data_url, timeout=120) as data_resp: |
| async for line_bytes in data_resp.content: |
| line = line_bytes.decode('utf-8').strip() |
| if line.startswith("data: "): |
| try: |
| json_data = json.loads(line[6:]) |
| if json_data.get("msg") == "process_completed": |
| if json_data.get("success"): |
| output_data = json_data.get("output", {}).get("data", []) |
| if output_data and len(output_data) > 0: |
| result_hist = output_data[0] |
| if isinstance(result_hist, list) and len(result_hist) > 0: |
| enhanced_prompt = result_hist[-1][1].strip() |
| break |
| except Exception: pass |
| except Exception: pass |
| if enhanced_prompt != prompt: break |
| await asyncio.sleep(2) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
| |
| w, h = 1024, 1024 |
| size_name = "مربع (1:1) ⬛" |
| if size_choice == "2": |
| w, h = 768, 1344 |
| size_name = "عمودی (9:16) 📱" |
| elif size_choice == "3": |
| w, h = 1344, 768 |
| size_name = "افقی (16:9) 🖥️" |
| elif size_choice == "4": |
| w, h = 1024, 768 |
| size_name = "استاندارد (4:3) 📸" |
|
|
| short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt |
| proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False) |
|
|
| generated_image = None |
| |
| for attempt in range(5): |
| keys_to_try = HF_TOKENS.copy() |
| random.shuffle(keys_to_try) |
| for token in keys_to_try: |
| try: |
| hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token) |
| generated_image = await hf_client.text_to_image( |
| enhanced_prompt, |
| model="Tongyi-MAI/Z-Image-Turbo", |
| width=w, |
| height=h |
| ) |
| break |
| except Exception as e: |
| continue |
| if generated_image: break |
| await asyncio.sleep(2) |
| |
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
|
|
| if not generated_image: |
| |
| error_msg = "⚠️ **منابع این بخش در حال افزایش است!**\nموقتاً این بخش در حال ارتقا است. فعلاً اعتباری از شما کم نشد، بهزودی این بخش در دسترس قرار خواهد گرفت." |
| return await send_with_keyboard(client, chat_id, error_msg, True) |
|
|
| try: |
| file_name = f"image_{uuid.uuid4().hex}.jpg" |
| await asyncio.to_thread(sync_save_image, generated_image, file_name) |
| await asyncio.sleep(1) |
| caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}" |
| |
| upload_result = False |
| for up_att in range(3): |
| res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text) |
| if res is True: |
| upload_result = True |
| break |
| else: |
| await asyncio.sleep(4) |
| |
| if upload_result is True: |
| |
| user_credits_db[str_chat_id]["image"] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ عکس ساخته شد اما آپلود در روبیکا با خطا مواجه شد.", True) |
| |
| if os.path.exists(file_name): os.remove(file_name) |
| except Exception as e: |
| await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره و ارسال عکس:\n{str(e)[:150]}", True) |
|
|
|
|
| |
| |
| |
| async def translate_text_aloha(prompt_text): |
| session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11)) |
| join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join" |
| payload = { |
| "data":[prompt_text, "انگلیسی (آمریکا) - جنی (زن)", 0, 0, 0], |
| "fn_index": 1, |
| "session_hash": session_hash |
| } |
| |
| try: |
| async with aiohttp.ClientSession() as session: |
| async with session.post(join_url, json=payload, timeout=20) as resp: |
| if resp.status != 200: |
| return prompt_text |
| |
| data_url = f"https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/data?session_hash={session_hash}" |
| async with session.get(data_url, timeout=60) as resp: |
| async for line_bytes in resp.content: |
| line = line_bytes.decode('utf-8').strip() |
| if line.startswith("data: "): |
| try: |
| json_data = json.loads(line[6:]) |
| if json_data.get("msg") == "process_completed": |
| if json_data.get("success"): |
| return json_data["output"]["data"][0] |
| break |
| except Exception: |
| pass |
| except Exception: |
| pass |
| |
| return prompt_text |
|
|
| async def process_image_edit(client, chat_id, image_bytes, prompt): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| |
| is_prem = creds.get("is_premium", False) |
| |
| |
| if not is_prem: |
| msg = """کاربر گرامی، |
| |
| ضمن تشکر از توجه شما، به اطلاع میرساند که قابلیت ویرایش تصاویر در حال حاضر به صورت رایگان در دسترس نمیباشد. این سرویس به دلیل نیاز به منابع پردازشی بالا، جزو خدمات ویژه و نیازمند تهیه اشتراک است. |
| |
| با این حال، شما میتوانید از تست رایگان و امکانات سایر بخشهای پلتفرم ما بهرهمند شوید. |
| |
| ما همواره در تلاش برای افزایش منابع و اضافه کردن خدمات رایگان بیشتر به کاربران عزیز هستیم. |
| |
| در حال حاضر، میتوانید از سایر بخشهای رایگان موجود استفاده کنید و یا برای دسترسی کامل و نامحدود به تمامی قابلیتها (از جمله ویرایش تصاویر)، اشتراک تهیه نمایید. |
| |
| از صبوری و همراهی شما سپاسگزاریم.""" |
| return await send_with_keyboard(client, chat_id, msg, False) |
|
|
| |
| if creds["edit_image"] <= 0: |
| msg = "⚠️ **اعتبار شما برای این بخش تمام شده است!**\nاز بقیه بخشها میتوانید نامحدود استفاده کنید. در حال افزایش منابع برای این بخش هستیم." |
| return await send_with_keyboard(client, chat_id, msg, False) |
|
|
| if not HF_TOKENS: |
| return await send_with_keyboard(client, chat_id, "❌ توکنهای هاگینگ فیس تنظیم نشدهاند.", False) |
|
|
| proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال ترجمه دستور شما توسط اسپیس و اعمال جادوی FLUX.2...\n(این فرآیند ممکن است کمی طول بکشد)", False) |
| |
| translated_prompt = await translate_text_aloha(prompt) |
| if not translated_prompt or translated_prompt.strip() == "": |
| translated_prompt = prompt |
|
|
| generated_image = None |
| |
| for attempt in range(5): |
| keys_to_try = HF_TOKENS.copy() |
| random.shuffle(keys_to_try) |
| for token in keys_to_try: |
| try: |
| hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token) |
| generated_image = await hf_client.image_to_image( |
| image_bytes, |
| prompt=translated_prompt, |
| model="black-forest-labs/FLUX.2-dev" |
| ) |
| break |
| except Exception as e: |
| continue |
| if generated_image: break |
| await asyncio.sleep(2) |
| |
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
|
|
| if not generated_image: |
| |
| error_msg = "⚠️ **منابع این بخش در حال افزایش است!**\nموقتاً این بخش در حال ارتقا است. فعلاً اعتباری از شما کم نشد، بهزودی این بخش در دسترس قرار خواهد گرفت." |
| return await send_with_keyboard(client, chat_id, error_msg, True) |
|
|
| try: |
| file_name = f"edited_flux_{uuid.uuid4().hex}.jpg" |
| await asyncio.to_thread(sync_save_image, generated_image, file_name) |
| await asyncio.sleep(1) |
| caption_text = f"🪄 ویرایش عکس با هوش مصنوعی Flux.2 انجام شد!\n\n✨ تغییرات خواسته شده: {prompt}\n🔤 متن ارسال شده به هوش: {translated_prompt}" |
| |
| upload_result = False |
| for up_att in range(3): |
| res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text) |
| if res is True: |
| upload_result = True |
| break |
| else: |
| await asyncio.sleep(4) |
| |
| if upload_result is True: |
| |
| user_credits_db[str_chat_id]["edit_image"] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ عکس ساخته شد اما خطا در ارسال به روبیکا رخ داد.", True) |
| |
| if os.path.exists(file_name): os.remove(file_name) |
| except Exception as e: |
| await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True) |
|
|
| |
| |
| |
| async def process_tts(client, chat_id, user_text, speaker_id, speaker_name): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| if creds["tts"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل متن به صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
|
|
| try: |
| proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False) |
| |
| |
| tts_url = "https://opera8-podgen.hf.space/api/generate" |
| payload = { |
| "text": user_text, |
| "speaker": speaker_id, |
| "temperature": 0.9, |
| "is_custom": False |
| } |
| headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"} |
| |
| audio_bytes = None |
| last_error = "پاسخی دریافت نشد" |
| |
| async with aiohttp.ClientSession(headers=headers, timeout=aiohttp.ClientTimeout(total=300)) as session: |
| for attempt in range(6): |
| try: |
| async with session.post(tts_url, json=payload) as response: |
| if response.status == 200: |
| content_type = response.headers.get('Content-Type', '') |
| if 'audio' in content_type or response.content_length > 1000: |
| audio_bytes = await response.read() |
| break |
| else: |
| last_error = "فایل نامعتبر" |
| elif response.status == 429: |
| await asyncio.sleep(4 + attempt * 2) |
| else: |
| last_error = f"ارور ({response.status})" |
| await asyncio.sleep(2) |
| except Exception as e: |
| last_error = f"خطا: {str(e)}" |
| await asyncio.sleep(2) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id, [msg_id]) |
| except Exception: pass |
|
|
| if audio_bytes: |
| |
| file_name_audio = f"audio_{uuid.uuid4().hex}.wav" |
| await asyncio.to_thread(sync_write_file, file_name_audio, audio_bytes) |
| await asyncio.sleep(1) |
| |
| upload_result_file = False |
| error_log_tts = "" |
| for up_att in range(3): |
| res = await helper_upload_file(client, chat_id, file_name_audio, "Music", "✅ صدای شما با موفقیت آماده شد:") |
| if res is True: |
| upload_result_file = True |
| break |
| else: |
| error_log_tts = res |
| await asyncio.sleep(4) |
| |
| if upload_result_file is True: |
| if not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["tts"] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, f"❌ فایل صدا ساخته شد اما سرور روبیکا اجازه آپلود نداد:\n`{str(error_log_tts)[:800]}`", True) |
| |
| if os.path.exists(file_name_audio): |
| os.remove(file_name_audio) |
| else: |
| await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True) |
| except Exception: |
| traceback.print_exc() |
|
|
| |
| |
| |
| async def process_podcast(client, chat_id, prompt): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| if creds["podcast"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت پادکست شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
|
|
| proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و شروع ساخت پادکست در سرور پردازشی...\n(با توجه به طولانی بودن این فرآیند، لطفاً چند دقیقه صبور باشید. ربات در حال انجام عملیات است)", False) |
| |
| available_speakers = [] |
| for num_key, (spk_name, spk_id) in SPEAKERS.items(): |
| gender = "male" if "مرد" in spk_name else "female" |
| available_speakers.append({"id": spk_id, "name": spk_name.split(' (')[0], "gender": gender}) |
|
|
| |
| url_create = "https://opera8-podgen.hf.space/api/auto-podcast" |
| payload_create = {"prompt": prompt, "available_speakers": available_speakers} |
| |
| async with aiohttp.ClientSession() as session: |
| task_id = None |
| |
| |
| for attempt in range(5): |
| try: |
| async with session.post(url_create, json=payload_create, timeout=60) as resp: |
| if resp.status == 202: |
| task_id = (await resp.json()).get("task_id") |
| break |
| elif resp.status == 429: |
| await asyncio.sleep(4 + attempt * 2) |
| else: |
| await asyncio.sleep(3) |
| except Exception as e: |
| await asyncio.sleep(3) |
| |
| if not task_id: |
| return await send_with_keyboard(client, chat_id, "❌ ارتباط با سرور پادکست در حال حاضر برقرار نشد. لطفاً چند دقیقه دیگر امتحان کنید.", True) |
|
|
| |
| url_status = f"https://opera8-podgen.hf.space/api/auto-podcast-status/{task_id}" |
| final_filename = None |
| last_progress_message = "" |
| |
| |
| for _ in range(500): |
| await asyncio.sleep(4) |
| try: |
| async with session.get(url_status, timeout=20) as resp: |
| if resp.status == 200: |
| status_data = await resp.json() |
| current_status = status_data.get("status") |
| progress_msg = status_data.get("progress", "") |
| |
| if current_status == "completed": |
| final_filename = status_data.get("filename") |
| break |
| |
| elif current_status == "failed": |
| error_detail = status_data.get("error", "نامشخص") |
| return await send_with_keyboard(client, chat_id, f"❌ سرور در ساخت پادکست با خطا مواجه شد.\nدلیل: {error_detail}", True) |
| |
| elif resp.status == 429: |
| await asyncio.sleep(5) |
| except Exception: |
| pass |
| |
| if not final_filename: |
| return await send_with_keyboard(client, chat_id, "❌ زمان انتظار برای ساخت پادکست به پایان رسید و سرور پاسخ نهایی را نداد.", True) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id, [msg_id]) |
| except: pass |
| |
| proc_msg = await send_with_keyboard(client, chat_id, "📥 پادکست ساخته شد! در حال دانلود فایل نهایی از سرور و آمادهسازی جهت ارسال...", False) |
|
|
| |
| download_url = f"https://opera8-podgen.hf.space/api/download-podcast/{final_filename}" |
| audio_bytes = None |
| |
| for attempt in range(5): |
| try: |
| async with session.get(download_url, timeout=300) as resp: |
| if resp.status == 200: |
| audio_bytes = await resp.read() |
| break |
| else: |
| await asyncio.sleep(4) |
| except Exception: |
| await asyncio.sleep(4) |
| |
| if not audio_bytes: |
| return await send_with_keyboard(client, chat_id, "❌ فایل پادکست آماده شد اما ربات نتوانست آن را از سرور دانلود کند.", True) |
|
|
| |
| file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3" |
| await asyncio.to_thread(sync_write_file, file_name_mp3, audio_bytes) |
| |
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id, [msg_id]) |
| except: pass |
|
|
| caption_file = f"🎧 فایل پادکست شما آماده است:\n\n💡 موضوع شما: {prompt}" |
| |
| upload_result_file = False |
| error_log_pod = "" |
| for up_att in range(3): |
| res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", caption_file) |
| if res is True: |
| upload_result_file = True |
| break |
| else: |
| error_log_pod = res |
| await asyncio.sleep(5) |
| |
| if upload_result_file is True: |
| if not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["podcast"] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, f"❌ پادکست دانلود شد اما روبیکا خطای آپلود داد.\n\n`{str(error_log_pod)[:800]}`", True) |
| |
| if os.path.exists(file_name_mp3): |
| os.remove(file_name_mp3) |
|
|
| |
| |
| |
| async def process_stt(client, chat_id, audio_bytes, file_name): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| if creds["stt"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل صدا به متن شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
|
|
| if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشدهاند.", False) |
| |
| proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیادهسازی متن...", False) |
| base64_data = base64.b64encode(audio_bytes).decode('utf-8') |
| mime_type, _ = mimetypes.guess_type(file_name) |
| if not mime_type: mime_type = "audio/ogg" |
| |
| prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبتهای داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافهای نده." |
| |
| transcribed_text = None |
| for attempt in range(5): |
| keys_to_try = get_next_gemini_keys(100) |
| async with aiohttp.ClientSession() as session: |
| for key in keys_to_try: |
| url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}" |
| payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.2}} |
| try: |
| async with session.post(url, json=payload, timeout=60) as response: |
| if response.status == 200: |
| data = await response.json() |
| transcribed_text = data["candidates"][0]["content"]["parts"][0]["text"] |
| break |
| except Exception: continue |
| if transcribed_text: break |
| await asyncio.sleep(2) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
|
|
| if transcribed_text: |
| sent = await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True) |
| if sent and not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["stt"] -= 1 |
| save_db(user_credits_db) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True) |
|
|
| async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| if creds["file"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ اعتبار تحلیل فایل شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
|
|
| if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False) |
| |
| proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False) |
| base64_data = base64.b64encode(file_bytes).decode('utf-8') |
| mime_type, _ = mimetypes.guess_type(file_name) |
| if not mime_type: |
| if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg" |
| elif file_name.endswith('.png'): mime_type = "image/png" |
| elif file_name.endswith('.pdf'): mime_type = "application/pdf" |
| elif file_name.endswith('.mp4'): mime_type = "video/mp4" |
| elif file_name.endswith('.mp3'): mime_type = "audio/mp3" |
| elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg" |
| elif file_name.endswith('.wav'): mime_type = "audio/wav" |
| else: mime_type = "image/jpeg" |
| |
| is_image = mime_type.startswith('image/') |
| |
| final_answer = None |
| for attempt in range(5): |
| keys_to_try = get_next_gemini_keys(100) |
| async with aiohttp.ClientSession() as session: |
| for key in keys_to_try: |
| url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}" |
| payload = {"contents": [{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.6}} |
| try: |
| async with session.post(url, json=payload, timeout=45) as response: |
| if response.status == 200: |
| data = await response.json() |
| final_answer = data["candidates"][0]["content"]["parts"][0]["text"] |
| break |
| except Exception: continue |
| if final_answer: break |
| await asyncio.sleep(2) |
|
|
| if not final_answer: |
| if is_image and HF_TOKENS: |
| for attempt in range(5): |
| keys_to_try_hf = HF_TOKENS.copy() |
| random.shuffle(keys_to_try_hf) |
| |
| hf_messages =[ |
| { |
| "role": "user", |
| "content":[ |
| {"type": "text", "text": prompt}, |
| { |
| "type": "image_url", |
| "image_url": {"url": f"data:{mime_type};base64,{base64_data}"} |
| } |
| ] |
| } |
| ] |
| |
| async with aiohttp.ClientSession() as session: |
| for hf_key in keys_to_try_hf: |
| url = "https://router.huggingface.co/v1/chat/completions" |
| headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"} |
| payload = { |
| "model": "google/gemma-4-31B-it:novita", |
| "messages": hf_messages, |
| "max_tokens": 4096 |
| } |
| try: |
| async with session.post(url, headers=headers, json=payload, timeout=60) as response: |
| if response.status == 200: |
| data = await response.json() |
| final_answer = data["choices"][0]["message"]["content"] |
| break |
| except Exception: |
| continue |
| if final_answer: break |
| await asyncio.sleep(2) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
|
|
| if final_answer: |
| sent = await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True) |
| if sent and not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["file"] -= 1 |
| save_db(user_credits_db) |
| else: |
| if not is_image: |
| await send_with_keyboard(client, chat_id, "❌ متأسفانه سرور اصلی در حال حاضر شلوغ است و در این شرایط **فعلاً تنها امکان تحلیل تصاویر** توسط سرور جایگزین در دسترس است.", True) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", True) |
|
|
| |
| |
| |
| async def process_create_file(client, chat_id, topic): |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
| |
| if creds["chat"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ اعتبار چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
|
|
| proc_msg = await send_with_keyboard(client, chat_id, "✍️ در حال تحقیق و نگارش مقاله جامع و حرفهای...\n(این عملیات با توجه به طولانی بودن متن ممکن است کمی طول بکشد)", False) |
|
|
| ai_prompt = f"یک مقاله بینهایت جامع، کاملاً حرفهای و بسیار بسیار طولانی درباره موضوع زیر به زبان فارسی بنویس. دقت کن که مقاله باید شامل بخشبندیهای متعدد باشد و توضیحات زیر هر عنوان باید به شدت طولانی، مفصل و با جزئیات و مثالهای فراوان (حداقل چند پاراگراف بلند برای هر بخش) نوشته شود؛ به هیچ وجه زیر عناوین توضیحات کوتاه نده. فقط متن اصلی مقاله را بده و هیچ توضیح اضافهای ننویس:\n\nموضوع: {topic}" |
| |
| article_text = None |
| session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11)) |
| join_url = "https://coherelabs-aya-expanse.hf.space/gradio_api/queue/join" |
| data_url = f"https://coherelabs-aya-expanse.hf.space/gradio_api/queue/data?session_hash={session_hash}" |
| |
| payload = { |
| "data": [ |
| ai_prompt, |
| [], |
| None, |
| None |
| ], |
| "event_data": None, |
| "fn_index": 2, |
| "session_hash": session_hash, |
| "trigger_id": 37 |
| } |
|
|
| for attempt in range(3): |
| try: |
| async with aiohttp.ClientSession() as session: |
| async with session.post(join_url, json=payload, timeout=30) as resp: |
| if resp.status == 200: |
| async with session.get(data_url, timeout=180) as data_resp: |
| async for line_bytes in data_resp.content: |
| line = line_bytes.decode('utf-8').strip() |
| if line.startswith("data: "): |
| try: |
| json_data = json.loads(line[6:]) |
| if json_data.get("msg") == "process_completed": |
| if json_data.get("success"): |
| output_data = json_data.get("output", {}).get("data", []) |
| if output_data and len(output_data) > 0: |
| result_hist = output_data[0] |
| if isinstance(result_hist, list) and len(result_hist) > 0: |
| article_text = result_hist[-1][1] |
| break |
| except Exception: pass |
| except Exception: pass |
| if article_text: break |
| await asyncio.sleep(2) |
|
|
| if not article_text: |
| return await send_with_keyboard(client, chat_id, "❌ سرور تولید متن شلوغ است، لطفاً بعداً تلاش کنید.", True) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
|
|
| proc_msg = await send_with_keyboard(client, chat_id, "📄 مقاله با موفقیت نوشته شد! در حال ارتباط با هوش مصنوعی و دریافت فایلهای PDF و Word...\n(لطفا صبور باشید)", False) |
|
|
| converter_url = "https://opera8-texttopdf.hf.space/" |
| uid = uuid.uuid4().hex |
|
|
| pdf_success = False |
| for attempt in range(30): |
| try: |
| pdf_bytes = None |
| async with aiohttp.ClientSession() as session: |
| form_data = aiohttp.FormData() |
| form_data.add_field('content', article_text) |
| form_data.add_field('format', 'pdf') |
| async with session.post(converter_url, data=form_data, timeout=90) as resp: |
| if resp.status == 200: |
| data_bytes = await resp.read() |
| if data_bytes and len(data_bytes) > 100: |
| pdf_bytes = data_bytes |
| |
| if pdf_bytes: |
| filename = f"Article_{uid}.pdf" |
| await asyncio.to_thread(sync_write_file, filename, pdf_bytes) |
| |
| res_upload = False |
| for _ in range(3): |
| r = await helper_upload_file(client, chat_id, filename, "File", f"📄 فایل PDF مقاله شما:\n\n💡 موضوع: {topic}") |
| if r is True: |
| res_upload = True |
| break |
| await asyncio.sleep(4) |
|
|
| if os.path.exists(filename): |
| os.remove(filename) |
| |
| if res_upload is True: |
| pdf_success = True |
| break |
| except Exception as e: |
| print(f"PDF error (attempt {attempt+1}):", e) |
| |
| await asyncio.sleep(4) |
|
|
| await asyncio.sleep(3.5) |
|
|
| docx_success = False |
| for attempt in range(30): |
| try: |
| docx_bytes = None |
| async with aiohttp.ClientSession() as session: |
| form_data = aiohttp.FormData() |
| form_data.add_field('content', article_text) |
| form_data.add_field('format', 'docx') |
| async with session.post(converter_url, data=form_data, timeout=90) as resp: |
| if resp.status == 200: |
| data_bytes = await resp.read() |
| if data_bytes and len(data_bytes) > 100: |
| docx_bytes = data_bytes |
| |
| if docx_bytes: |
| filename = f"Article_{uid}.docx" |
| await asyncio.to_thread(sync_write_file, filename, docx_bytes) |
| |
| res_upload = False |
| for _ in range(3): |
| r = await helper_upload_file(client, chat_id, filename, "File", f"📝 فایل Word (DOCX) مقاله شما:\n\n💡 موضوع: {topic}") |
| if r is True: |
| res_upload = True |
| break |
| await asyncio.sleep(4) |
|
|
| if os.path.exists(filename): |
| os.remove(filename) |
| |
| if res_upload is True: |
| docx_success = True |
| break |
| except Exception as e: |
| print(f"DOCX error (attempt {attempt+1}):", e) |
| |
| await asyncio.sleep(4) |
|
|
| try: |
| if proc_msg: |
| msg_id = getattr(proc_msg, 'message_id', None) |
| if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id') |
| if msg_id: await client.delete_messages(chat_id,[msg_id]) |
| except Exception: pass |
|
|
| if pdf_success and docx_success: |
| if not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["chat"] -= 1 |
| save_db(user_credits_db) |
| await send_with_keyboard(client, chat_id, "✅ مقاله شما با موفقیت به صورت هر دو فایل (PDF و Word) تحویل داده شد!", True) |
| elif pdf_success or docx_success: |
| if not creds.get("is_premium"): |
| user_credits_db[str_chat_id]["chat"] -= 1 |
| save_db(user_credits_db) |
| await send_with_keyboard(client, chat_id, "⚠️ یکی از فایلها با موفقیت ارسال شد اما دیگری پس از تلاشهای مکرر سرور با خطا مواجه شد.", True) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ متأسفانه پس از تلاشهای مکرر، سرور قادر به ساخت و ارسال هیچیک از فایلها نبود و اعتباری از شما کسر نشد.", True) |
|
|
| |
| |
| |
| |
| |
| |
|
|
| BOT_START_TIME = time.time() |
|
|
| |
| async def ram_garbage_collector(): |
| """این تابع در پسزمینه میچرخد و فایلهای رها شده در حافظه را پاک میکند تا رم سرور پر نشود""" |
| while True: |
| await asyncio.sleep(1800) |
| now = time.time() |
| try: |
| |
| for uid in list(user_states.keys()): |
| if now - user_states[uid].get("last_time", 0) > 3600: |
| if user_states[uid].get("file_bytes") is not None: |
| user_states[uid]["file_bytes"] = None |
| if user_states[uid].get("ref_bytes") is not None: |
| user_states[uid]["ref_bytes"] = None |
| if len(user_states[uid].get("history",[])) > 5: |
| user_states[uid]["history"] = user_states[uid]["history"][-5:] |
| |
| |
| for uid in list(user_message_times.keys()): |
| times = user_message_times[uid] |
| valid_times =[t for t in times if now - t < 3.0] |
| if not valid_times: |
| del user_message_times[uid] |
| else: |
| user_message_times[uid] = valid_times |
| |
| except Exception as e: |
| pass |
|
|
| if not bot_token: |
| print("خطا: توکن ربات روبیکا وارد نشده است!") |
| else: |
| bot = BotClient(bot_token) |
|
|
| @bot.on_update(filters.private) |
| async def main_handler(client, update): |
| global BOT_GUID |
| |
| try: |
| if not BOT_GUID: |
| try: |
| me_info = await client.get_me() |
| if me_info and hasattr(me_info, 'user'): |
| BOT_GUID = getattr(me_info.user, 'user_guid', None) |
| except Exception: |
| pass |
|
|
| msg_obj = getattr(update, "message", None) or getattr(update, "new_message", None) |
| |
| author_id = getattr(update, 'author_guid', None) |
| if not author_id and msg_obj: |
| author_id = msg_obj.get('author_object_guid') if isinstance(msg_obj, dict) else getattr(msg_obj, 'author_object_guid', None) |
| |
| if BOT_GUID and author_id == BOT_GUID: |
| return |
| |
| chat_id = getattr(update, 'object_guid', None) or getattr(update, 'author_guid', None) or getattr(update, "chat_id", None) |
| if not chat_id: return |
| |
| msg_id = getattr(update, "message_id", None) |
| if not msg_id and msg_obj: |
| msg_id = msg_obj.get("message_id") if isinstance(msg_obj, dict) else getattr(msg_obj, "message_id", None) |
| |
| str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip() |
| creds = get_user_credits(str_chat_id) |
|
|
| |
| |
| |
| if msg_id: |
| str_msg_id = str(msg_id).strip() |
| if is_message_processed(str_msg_id): |
| return |
| |
| |
| is_old = False |
| try: |
| for attr in['timestamp', 'time', 'date', 'message_date']: |
| val = getattr(msg_obj, attr, None) |
| if not val and isinstance(msg_obj, dict): |
| val = msg_obj.get(attr) |
| if val: |
| val_int = int(val) |
| |
| if val_int > 10000000000: |
| val_int = val_int / 1000 |
| |
| |
| if val_int < BOT_START_TIME - 60: |
| is_old = True |
| break |
| except Exception: |
| pass |
|
|
| |
| mark_message_processed(str_msg_id) |
|
|
| if is_old: |
| |
| return |
| |
|
|
| user_text = getattr(update, "text", "") or getattr(msg_obj, "text", "") |
| user_text_str = str(user_text).strip() if user_text else "" |
| user_text_lower = user_text_str.lower() |
|
|
| if is_user_spamming(str_chat_id): |
| return |
|
|
| if str_chat_id not in user_states: |
| user_states[str_chat_id] = {"mode": None, "text": "", "history":[], "file_bytes": None, "file_name": None, "last_time": time.time()} |
| else: |
| user_states[str_chat_id]["last_time"] = time.time() |
|
|
| if user_text_lower.startswith(f"{ADMIN_CODE} pro=") or user_text_lower.startswith(f"{ADMIN_CODE}pro="): |
| parts = user_text_str.split("=", 1) |
| if len(parts) >= 2: |
| target_id = parts[1].replace("`", "").replace("'", "").replace('"', "").strip() |
| if target_id: |
| if target_id not in user_credits_db or not isinstance(user_credits_db[target_id], dict): |
| user_credits_db[target_id] = { |
| "is_premium": False, |
| "expire_date": None, |
| "last_reset": "", |
| "chat": 10, |
| "image": 0, |
| "edit_image": 0, |
| "podcast": 2, |
| "tts": 5, |
| "file": 1, |
| "stt": 5, |
| "voice_conv": 3, |
| "voice_clone": 1, |
| "last_msg_id": 0, |
| "has_joined": True, |
| "invited_count": 0, |
| "used_referral": False, |
| "referral_code": "" |
| } |
| |
| user_credits_db[target_id]["is_premium"] = True |
| expire_time = datetime.datetime.now() + datetime.timedelta(days=30) |
| user_credits_db[target_id]["expire_date"] = expire_time.isoformat() |
| |
| user_credits_db[target_id]["chat"] = 999999 |
| user_credits_db[target_id]["image"] = 10 |
| user_credits_db[target_id]["edit_image"] = 5 |
| user_credits_db[target_id]["podcast"] = 999999 |
| user_credits_db[target_id]["tts"] = 999999 |
| user_credits_db[target_id]["file"] = 999999 |
| user_credits_db[target_id]["stt"] = 999999 |
| user_credits_db[target_id]["voice_conv"] = 999999 |
| user_credits_db[target_id]["voice_clone"] = 999999 |
| |
| save_db(user_credits_db) |
| await send_with_keyboard(client, chat_id, f"✅ حساب کاربر `{target_id}` به مدت ۳۰ روز شارژ شد و به پرو ارتقا یافت.", False) |
| try: |
| await send_with_keyboard(client, target_id, "🎉 **کاربر گرامی، تبریک!**\n\nحساب شما با موفقیت توسط پشتیبانی به **🌟 نسخه پرو (ویژه)** ارتقا یافت.\nهماکنون بستههای نامحدود و طلایی یکماهه شما فعال گردید.\n\nجهت مشاهده جزئیات روی دکمه «حساب کاربری 👤» کلیک کنید.", True) |
| except Exception: pass |
| return |
| |
| if user_text_lower.startswith(f"{ADMIN_CODE} free=") or user_text_lower.startswith(f"{ADMIN_CODE}free="): |
| parts = user_text_str.split("=", 1) |
| if len(parts) >= 2: |
| target_id = parts[1].replace("`", "").replace("'", "").replace('"', "").strip() |
| if target_id: |
| if target_id in user_credits_db and isinstance(user_credits_db[target_id], dict): |
| user_credits_db[target_id]["is_premium"] = False |
| user_credits_db[target_id]["expire_date"] = None |
| user_credits_db[target_id]["last_reset"] = "" |
| user_credits_db[target_id]["image"] = 0 |
| user_credits_db[target_id]["edit_image"] = 0 |
| save_db(user_credits_db) |
| await send_with_keyboard(client, chat_id, f"✅ اشتراک کاربر `{target_id}` لغو شد و به رایگان تبدیل گشت.", False) |
| try: |
| await send_with_keyboard(client, target_id, "⚠️ کاربر گرامی، اشتراک ویژه شما به پایان رسید و حساب شما به نسخه رایگان (آزمایشی) تغییر یافت.", True) |
| except Exception: pass |
| return |
|
|
| if user_text_lower.startswith(f"{ADMIN_CODE} =") or user_text_lower.startswith(f"{ADMIN_CODE}="): |
| parts = user_text_str.split("=", 1) |
| if len(parts) >= 2: |
| target_id = parts[1].replace("`", "").replace("'", "").replace('"', "").strip() |
| if target_id: |
| if target_id in user_credits_db and isinstance(user_credits_db[target_id], dict): |
| t_creds = user_credits_db[target_id] |
| is_prem = t_creds.get("is_premium", False) |
| |
| if is_prem: |
| expire_txt = "نامشخص" |
| days_left = 0 |
| if t_creds.get("expire_date"): |
| exp_d = datetime.datetime.fromisoformat(t_creds["expire_date"]) |
| now = datetime.datetime.now() |
| diff = exp_d - now |
| days_left = diff.days if diff.days >= 0 else 0 |
| |
| jy, jm, jd = gregorian_to_jalali(exp_d.year, exp_d.month, exp_d.day) |
| expire_txt = f"{jy:04d}/{jm:02d}/{jd:02d}" |
| status_text = f"🌟 نسخه پرو (ویژه)\n📅 انقضا: {expire_txt}\n⏳ باقیمانده: {days_left} روز" |
| else: |
| status_text = "🥉 نسخه رایگان (آزمایشی)\n⏳ وضعیت: سهمیه روزانه محدود" |
|
|
| chat_rem = "نامحدود ∞" if is_prem else t_creds.get('chat', 0) |
| vc_rem = "نامحدود ∞" if is_prem else t_creds.get('voice_conv', 0) |
| clone_rem = "نامحدود ∞" if is_prem else t_creds.get('voice_clone', 0) |
| podcast_rem = "نامحدود ∞" if is_prem else t_creds.get('podcast', 0) |
| tts_rem = "نامحدود ∞" if is_prem else t_creds.get('tts', 0) |
| file_rem = "نامحدود ∞" if is_prem else t_creds.get('file', 0) |
| stt_rem = "نامحدود ∞" if is_prem else t_creds.get('stt', 0) |
| image_rem = t_creds.get('image', 0) |
| edit_image_rem = t_creds.get('edit_image', 0) |
| invs = t_creds.get('invited_count', 0) |
| joined_status = "بله ✅" if t_creds.get('has_joined') else "خیر ❌" |
|
|
| info_msg = f"""🔍 **اطلاعات اختصاصی کاربر:** |
| 👤 شناسه: `{target_id}` |
| عضو کانال: {joined_status} |
| |
| 🔹 **وضعیت اشتراک:** |
| {status_text} |
| 🎁 **تعداد افراد دعوت شده:** {invs} نفر |
| |
| 📊 **سهمیه باقیمانده فعلی:** |
| 💬 چت: {chat_rem} |
| 🎨 تولید عکس: {image_rem} |
| 🪄 ویرایش عکس: {edit_image_rem} |
| 🎙️ تغییر صدا: {vc_rem} |
| 👤 کلون کردن صدا: {clone_rem} |
| 🎙 پادکست: {podcast_rem} |
| 🗣 متن به صدا: {tts_rem} |
| 📁 تحلیل فایل: {file_rem} |
| 📝 صدا به متن: {stt_rem}""" |
| await send_with_keyboard(client, chat_id, info_msg, False) |
| else: |
| await send_with_keyboard(client, chat_id, f"❌ کاربری با شناسه `{target_id}` در دیتابیس ربات یافت نشد.", False) |
| return |
|
|
| is_file = False |
| file_name = f"unknown_file_{uuid.uuid4().hex[:6]}.jpg" |
| |
| if msg_obj: |
| for attr in['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']: |
| file_attr = getattr(msg_obj, attr, None) |
| if file_attr: |
| is_file = True |
| file_name = getattr(file_attr, 'file_name', file_name) |
| break |
| |
| if not is_file and hasattr(msg_obj, 'to_dict'): |
| msg_dict = msg_obj.to_dict() |
| for attr in['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']: |
| if attr in msg_dict: |
| is_file = True |
| file_attr = msg_dict.get(attr, {}) |
| file_name = file_attr.get('file_name', file_name) if isinstance(file_attr, dict) else file_name |
| break |
|
|
| if user_text_str == "✅ عضو شدم": |
| if not creds.get("has_joined", False): |
| user_credits_db[str_chat_id]["has_joined"] = True |
| save_db(user_credits_db) |
| await send_with_keyboard(client, chat_id, "🎉 **عضویت شما با موفقیت تایید شد! خیلی خوش آمدید.**\n\nحالا میتوانید از تمامی امکانات ربات استفاده کنید.\nلطفاً یکی از گزینههای منو را انتخاب کنید:", True) |
| return |
| else: |
| await send_with_keyboard(client, chat_id, "✅ شما قبلاً عضو شدهاید! لطفا از منوی اصلی استفاده کنید.", True) |
| return |
|
|
| if not creds.get("has_joined", False): |
| join_msg = "👋 **سلام کاربر گرامی!**\n\nجهت استفاده از خدمات ربات هوش مصنوعی آلفا و مطلع شدن از آخرین آپدیتها، لطفا ابتدا در کانال رسمی ما عضو شوید:\n\n📢 **آیدی کانال:** @aialpha\n\n👇 پس از عضویت در کانال، بر روی دکمه **«✅ عضو شدم»** کلیک کنید تا ربات برای شما فعال شود." |
| try: |
| payload = {"chat_id": chat_id, "text": join_msg, "chat_keypad_type": "New", "chat_keypad": JOIN_KEYPAD_DICT} |
| await client._make_request("sendMessage", payload) |
| except Exception: |
| await client.send_message(chat_id, join_msg) |
| return |
|
|
| if user_text_lower.startswith("/start"): |
| user_states[str_chat_id]["mode"] = None |
| user_states[str_chat_id]["file_bytes"] = None |
| await send_with_keyboard(client, chat_id, "سلام! به ربات هوش مصنوعی آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخشها را انتخاب کنید:", True) |
| return |
|
|
| if user_text_str in["سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]: |
| user_states[str_chat_id]["mode"] = None |
| user_states[str_chat_id]["file_bytes"] = None |
| await send_with_keyboard(client, chat_id, "سلام! به ربات هوش مصنوعی آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخشها را انتخاب کنید:", True) |
| return |
|
|
| if user_text_str in["/account", "حساب کاربری 👤"]: |
| is_prem = creds.get("is_premium", False) |
| |
| if is_prem: |
| expire_txt = "نامشخص" |
| days_left = 0 |
| if creds.get("expire_date"): |
| exp_d = datetime.datetime.fromisoformat(creds["expire_date"]) |
| now = datetime.datetime.now() |
| diff = exp_d - now |
| days_left = diff.days if diff.days >= 0 else 0 |
| |
| jy, jm, jd = gregorian_to_jalali(exp_d.year, exp_d.month, exp_d.day) |
| expire_txt = f"{jy:04d}/{jm:02d}/{jd:02d} (ساعت {exp_d.hour:02d}:{exp_d.minute:02d})" |
| |
| status_text = "🌟 نسخه پرو (ویژه)" |
| expire_info = f"\n📅 **تاریخ انقضا:** {expire_txt}\n⏳ **زمان باقیمانده:** {days_left} روز" |
| daily_note = "*نکته: سهمیه پردازشی شما مختص همین دوره یکماهه میباشد.*" |
| else: |
| status_text = "🥉 نسخه رایگان (آزمایشی)" |
| expire_info = "" |
| daily_note = "*نکته: سهمیه شما هر روز ساعت ۰۰:۰۰ بامداد به صورت خودکار مجدداً شارژ میگردد.*" |
|
|
| chat_rem = "نامحدود ∞" if is_prem else creds['chat'] |
| vc_rem = "نامحدود ∞" if is_prem else creds.get('voice_conv', 0) |
| clone_rem = "نامحدود ∞" if is_prem else creds.get('voice_clone', 0) |
| podcast_rem = "نامحدود ∞" if is_prem else creds['podcast'] |
| tts_rem = "نامحدود ∞" if is_prem else creds['tts'] |
| file_rem = "نامحدود ∞" if is_prem else creds['file'] |
| stt_rem = "نامحدود ∞" if is_prem else creds['stt'] |
| image_rem = creds['image'] |
| edit_image_rem = creds['edit_image'] |
| invited_count = creds.get('invited_count', 0) |
| my_code = get_or_create_referral_code(str_chat_id) |
|
|
| account_profile = f"""👤 **اطلاعات حساب کاربری شما** |
| |
| 🔹 **شناسه یکتا:** `{chat_id}` |
| 🎫 **کد هدیه شما:** `{my_code}` |
| 🔹 **وضعیت اشتراک:** {status_text}{expire_info} |
| 🎁 **تعداد افراد دعوت شده:** {invited_count} نفر |
| |
| 📊 **سهمیه باقیمانده شما:** |
| - 💬 چت هوشمند: {chat_rem} |
| - 🎨 تولید تصویر: {image_rem} عدد |
| - 🪄 ویرایش تصویر: {edit_image_rem} عدد |
| - 🎙️ تغییر صدا: {vc_rem} |
| - 👤 کلون کردن صدا: {clone_rem} |
| - 🎙 ساخت پادکست: {podcast_rem} |
| - 🗣 تبدیل متن به صدا: {tts_rem} |
| - 📁 تحلیل فایل و سند: {file_rem} |
| - 📝 تبدیل صدا به متن: {stt_rem} |
| |
| {daily_note}""" |
| await send_with_keyboard(client, chat_id, account_profile, True) |
| return |
|
|
| if user_text_str in["/invite", "دعوت دوستان 🎁"]: |
| invites = creds.get("invited_count", 0) |
| remains = 10 - (invites % 10) |
| my_code = get_or_create_referral_code(str_chat_id) |
| |
| invite_text = f"""🎁 **سیستم دعوت دوستان (دو سر سود)** |
| |
| با دعوت دوستان خود به ربات آلفا، هم شما و هم دوستتان هدیه میگیرید! |
| به دوست خود بگویید پس از ورود به ربات، دکمه **«ثبت کد هدیه 🎫»** را بزند و کد زیر را وارد کند. |
| ✨ **سود دوست شما:** در همان لحظه 10 تبدیل رایگان متن به صدا دریافت میکند. |
| ✨ **سود شما:** به آمار دعوتهایتان اضافه میشود و به ازای هر **10 نفر**، **3 روز اشتراک پرو نامحدود** میگیرید. |
| |
| 📊 **آمار شما:** |
| - تعداد دعوتهای موفق: {invites} نفر |
| - دعوتهای باقیمانده تا جایزه بعدی: {remains} نفر |
| |
| کد هدیه اختصاصی شما: |
| `{my_code}` |
| |
| (متن زیر را کپی کرده و برای دوستانتان بفرستید 👇)""" |
| await send_with_keyboard(client, chat_id, invite_text, True) |
| |
| forward_text = f"""🤖 **ربات هوش مصنوعی آلفا پرو** |
| |
| ✨ با این ربات میتونی کارهای زیر رو به راحتی انجام بدی: |
| 💬 چت با پیشرفتهترین هوش مصنوعی |
| 🎨 ساخت و ویرایش حرفهای عکس |
| 🎙️ تغییر صدا و کلون کردن صدا |
| 🎙 ساخت پادکست اختصاصی |
| 🗣 تبدیل متن به صدا (30 گوینده مختلف) |
| 📝 تبدیل صدا و ویدیو به متن |
| 📁 تحلیل فایلها و ساخت مقاله |
| |
| 👇 اول وارد ربات زیر شو: |
| @aialphabot |
| |
| سپس دکمه **«ثبت کد هدیه 🎫»** را بزن و کد 8 رقمی زیر رو وارد کن تا همون اول **10 تا تبدیل صدا هدیه بگیری**: |
| `{my_code}`""" |
| await send_with_keyboard(client, chat_id, forward_text, False) |
| return |
|
|
| if user_text_str in["/referral", "ثبت کد هدیه 🎫"]: |
| if creds.get("used_referral", False): |
| await send_with_keyboard(client, chat_id, "❌ شما قبلاً کد هدیه یک نفر را ثبت کردهاید و فقط یکبار مجاز به استفاده از این امکان هستید.", True) |
| return |
| user_states[str_chat_id]["mode"] = "waiting_for_referral_code" |
| msg = "🎫 **ثبت کد هدیه**\n\nکد هدیه 8 رقمی (اعداد) که از دوست خود دریافت کردهاید را اینجا وارد کنید تا در همان لحظه **10 سهمیه تبدیل رایگان متن به صدا** هدیه بگیرید!\n\n(برای انصراف دکمه «برگشت♻️» را بزنید)" |
| await send_with_keyboard(client, chat_id, msg, True) |
| return |
|
|
| if user_text_str in["/buy", "خرید اشتراک 💎"]: |
| buy_text = f"""💎 **خرید اشتراک ویژه آلفا پرو (یک ماهه)** |
| |
| با تهیه اشتراک ویژه، محدودیتها را کنار بزنید و از نهایت قدرت هوش مصنوعی لذت ببرید! 🚀 |
| |
| ━━━━━━━━━━━━━━━━━━━ |
| 🎁 **بسته طلایی یکماهه شامل:** |
| 🤖 چت با هوش مصنوعی: نامحدود ∞ |
| 🎙️ تغییر صدا و کلون کردن صدا: نامحدود ∞ |
| 🗣 تبدیل متن به صدا (۳۰ گوینده): نامحدود ∞ |
| 🎙 ساخت پادکست: نامحدود ∞ |
| 📁 تحلیل فایل و سند: نامحدود ∞ |
| 📝 تبدیل فایل صوتی به متن: نامحدود ∞ |
| 🪄 ویرایش تصویر: 5 عدد |
| 🎨 تولید تصویر: 10 عدد |
| ━━━━━━━━━━━━━━━━━━━ |
| |
| 💳 **هزینه اشتراک یک ماهه:** 250 هزار تومان |
| |
| 💳 **شماره کارت جهت واریز:** |
| ➖➖➖➖➖➖➖➖ |
| `6219861411958035` |
| ➖➖➖➖➖➖➖➖ |
| 👤 **به نام:** کوهی |
| |
| ✅ **نحوه فعالسازی:** |
| پس از واریز مبلغ، لطفاً رسید پرداختی را به همراه **شناسه یکتای خود** (که در پایین آمده) به آیدی پشتیبانی زیر ارسال کنید تا اشتراک شما فعال گردد: |
| |
| 🔑 **شناسه یکتای شما:** |
| `{chat_id}` |
| |
| 👨💻 **ارتباط با پشتیبانی:** |
| 🆔 @aialpha_admin""" |
| await send_with_keyboard(client, chat_id, buy_text, True) |
| return |
|
|
| if user_text_str in["/transfer", "انتقال اکانت از برنامه به ربات"]: |
| transfer_text = f"""🔄 **انتقال اکانت از برنامه به ربات** |
| |
| کاربر گرامی، در صورتی که داخل برنامه «هوش مصنوعی آلفا» پیشتر اشتراک تهیه کردهاید، نیازی به خرید مجدد اشتراک داخل ربات نیست! 🎉 |
| |
| کافیست **شناسه یکتای** ربات روبیکای خود را کپی کرده و برای پشتیبانی ما در برنامه هوش مصنوعی آلفا ارسال کنید تا اکانت اشتراکی شما به سرعت از برنامه به ربات روبیکا انتقال داده شود. |
| |
| 🔑 **شناسه یکتای ربات شما:** |
| `{chat_id}` |
| |
| 👨💻 **دقت کنید شناسه ربات رو به پشتیبانی داخل خود برنامه هوش مصنوعی آلفا ارسال کنید.**""" |
| await send_with_keyboard(client, chat_id, transfer_text, True) |
| return |
|
|
| if user_text_str in["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]: |
| user_states[str_chat_id]["mode"] = "chat" |
| user_states[str_chat_id]["history"] =[] |
| await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n\nهر سوالی دارید بفرستید تا جواب بدم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| if user_text_str in["/image", "🎨 عکس", "ساخت تصاویر🎨"]: |
| user_states[str_chat_id]["mode"] = "image_waiting_for_text" |
| await send_with_keyboard(client, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\nمتن (ایده) خود را به صورت کامل ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| if user_text_str in["/edit_image", "ویرایش تصاویر 🪄"]: |
| if not creds.get("is_premium", False): |
| msg = """کاربر گرامی، |
| |
| ضمن تشکر از توجه شما، به اطلاع میرساند که قابلیت ویرایش تصاویر در حال حاضر به صورت رایگان در دسترس نمیباشد. این سرویس به دلیل نیاز به منابع پردازشی بالا، جزو خدمات ویژه و نیازمند تهیه اشتراک است. |
| |
| با این حال، شما میتوانید از تست رایگان و امکانات سایر بخشهای پلتفرم ما بهرهمند شوید. |
| |
| ما همواره در تلاش برای افزایش منابع و اضافه کردن خدمات رایگان بیشتر به کاربران عزیز هستیم. |
| |
| در حال حاضر، میتوانید از سایر بخشهای رایگان موجود استفاده کنید و یا برای دسترسی کامل و نامحدود به تمامی قابلیتها (از جمله ویرایش تصاویر)، اشتراک تهیه نمایید. |
| |
| از صبوری و همراهی شما سپاسگزاریم.""" |
| await send_with_keyboard(client, chat_id, msg, False) |
| return |
| |
| user_states[str_chat_id]["mode"] = "image_edit_waiting_for_image" |
| user_states[str_chat_id]["file_bytes"] = None |
| await send_with_keyboard(client, chat_id, "🪄 به بخش **ویرایش عکس (Flux.2)** خوش آمدید.\n\nلطفاً ابتدا عکسی که میخواهید ویرایش کنید را بفرستید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| if user_text_str in ["/tts", "🎙️ صدا", "تبدیل متن به صدا🗣️"]: |
| user_states[str_chat_id]["mode"] = "tts_waiting_for_text" |
| tts_msg = """🎙️ شما وارد بخش **تبدیل متن به صدا** شدید. |
| |
| |
| 📝 لطفاً متنی که میخواهید به صدا تبدیل شود را ارسال کنید. |
| |
| 🌍 **پشتیبانی از تمامی زبانهای دنیا!** |
| 🎭 **درک لحن و احساسات:** |
| هوش مصنوعی ما احساسات رو درک میکنه! کافیه لحن دلخواهت رو داخل پرانتز بنویسی. |
| 💡 *مثال:* هی، گوش کن! یه راز دارم که فقط به تو میگم. (با لحنی مرموز، شیطنتآمیز و نجواگونه) |
| |
| (برای خروج دکمه «برگشت♻️» را بزنید)""" |
| await send_with_keyboard(client, chat_id, tts_msg, True) |
| return |
| |
| if user_text_str in ["/podcast", "📻 پادکست", "ساخت پادکست 🎙️"]: |
| user_states[str_chat_id]["mode"] = "podcast_waiting_for_topic" |
| podcast_msg = """📻 شما وارد بخش **ساخت پادکست** شدید. |
| |
| لطفاً موضوع پادکست خود را بفرستید. این بخش متصل به هوش مصنوعی زبانی است و درخواست شما را قبل از ساخت کاملاً درک میکند! 🧠 |
| |
| ➖➖➖➖➖➖➖➖➖➖ |
| 💡 **راهنمای استفاده:** |
| 🔹 میتوانید فقط یک موضوع بدهید (مثال: درباره تاریخچه پیدایش قهوه با سه گوینده یک پادکست جذاب بساز). |
| 🔹 میتوانید متن کامل یک مقاله از یک سایت را بفرستید تا هوش مصنوعی خودش محتوای اصلی را استخراج کرده و پادکست بسازد. |
| 🔹 امکان مشخص کردن تعداد گویندگان و اسم آنها به انتخاب شما وجود دارد! |
| |
| ➖➖➖➖➖➖➖➖➖➖ |
| 🎙️ **لیست ۳۰ گوینده اختصاصی ما:** |
| شهاب | آوا | نوید | آرمان | مهسا | دانا | سامان | آرش | شبنم | سحر | مریم | بهرام | نیکان | فرناز | سارا | مانی | آرتین | دلنواز | روژان | امید | بردیا | ترانه | نیکو | هستی | کامیار | کیانوش | پویا | مهتاب | سام | لیدا |
| |
| ➖➖➖➖➖➖➖➖➖➖ |
| 📌 **مثال برای درخواست:** |
| یک پادکست برام بساز در باره مدیریت زمان با دو گوینده امید و مهسا |
| اگر گوینده و تعداد آن از سمت شما مشخص نشه هوش مصنوعی خودش انتخاب میکنه |
| |
| (برای خروج دکمه «برگشت♻️» را بزنید)""" |
| await send_with_keyboard(client, chat_id, podcast_msg, True) |
| return |
|
|
| if user_text_str in["/vc", "تغییر صدا 🎙️"]: |
| user_states[str_chat_id]["mode"] = "vc_waiting_for_voice" |
| user_states[str_chat_id]["file_bytes"] = None |
| await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تغییر صدا** شدید.\n\nلطفاً صدای خود (ویس) را بفرستید تا آن را به صدای شخصیتهای معروف تبدیل کنم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| if user_text_str in["/clone", "کلون کردن صدا 👤"]: |
| user_states[str_chat_id]["mode"] = "clone_waiting_for_src" |
| user_states[str_chat_id]["file_bytes"] = None |
| user_states[str_chat_id]["ref_bytes"] = None |
| clone_text = """👤 **شما وارد بخش کلون کردن صدای اختصاصی شدید. با یک فایل صوتی کوتاه از هر شخصی صدای خودتونو به همون صدا تغییر بدید.** |
| |
| ✨ **این بخش چه کاری انجام میدهد؟** |
| با این ویژگی بینظیر، شما میتوانید صدای خود (یا هر فرد دیگری) را دقیقاً شبیهسازی کنید! کافیست یک نمونه از صدای خودتان صحبت کنید و یک نمونه از صدای شخص مورد نظر (الگو) را به هوش مصنوعی بدهید. ربات لحن و کلمات شما را گرفته و دقیقاً با جنس صدای شخص الگو بازسازی میکند. |
| |
| 📌 **راهنمای استفاده:** |
| شما در این مرحله به **2 فایل صوتی** نیاز دارید: |
| 1️⃣ **صدای ورودی (شما):** صدایی که میخواهید متن و لحن آن خوانده شود. |
| 2️⃣ **صدای الگو (هدف):** صدایی که میخواهید خروجی نهایی شبیه به آن شود (بدون نویز و موزیک پسزمینه، بین ۳ تا ۱۰ ثانیه بهترین نتیجه را میدهد). |
| |
| 👇 **مرحله اول:** |
| لطفاً ابتدا **صدای خودتان (ورودی)** را به صورت ویس یا فایل صوتی ارسال کنید: |
| |
| *(برای خروج دکمه «برگشت♻️» را بزنید)*""" |
| await send_with_keyboard(client, chat_id, clone_text, True) |
| return |
|
|
| if user_text_str in["/file", "تحلیل فایل 📁"]: |
| user_states[str_chat_id]["mode"] = "file_waiting_for_file" |
| user_states[str_chat_id]["file_bytes"] = None |
| await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً فایل خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| if user_text_str in["/stt", "فایل صوتی به متن 📝"]: |
| user_states[str_chat_id]["mode"] = "stt_waiting_for_audio" |
| await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| if user_text_str in["/create_file", "ساخت فایل 📄"]: |
| user_states[str_chat_id]["mode"] = "create_file_waiting_for_topic" |
| await send_with_keyboard(client, chat_id, "📄 شما وارد بخش **ساخت فایل** شدید.\n\nلطفاً موضوع مقالهای که میخواهید را کامل بفرستید.\nمثال: نحوه مدیریت زمان\n\nهوش مصنوعی یک مقاله کامل و طولانی نوشته و در نهایت فایل PDF و Word آن را به شما تحویل میدهد.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True) |
| return |
|
|
| current_mode = user_states[str_chat_id].get("mode") |
|
|
| if current_mode is None: |
| if is_file: pass |
| elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True) |
| return |
|
|
| elif current_mode == "waiting_for_referral_code": |
| if user_text_str: |
| normalized_code = to_english_digits(user_text_str).strip() |
| |
| if not normalized_code.isdigit() or len(normalized_code) != 8: |
| await send_with_keyboard(client, chat_id, "❌ کد وارد شده نامعتبر است. لطفاً یک کد 8 رقمی صحیح بفرستید.", False) |
| return |
| |
| inviter_id = find_user_by_referral_code(normalized_code) |
| |
| if not inviter_id: |
| await send_with_keyboard(client, chat_id, "❌ کد هدیه یافت نشد. لطفاً کد را با دقت بررسی کنید.", False) |
| return |
| |
| if str(inviter_id) == str(str_chat_id): |
| await send_with_keyboard(client, chat_id, "❌ شما نمیتوانید کد خودتان را ثبت کنید!", False) |
| return |
| |
| user_states[str_chat_id]["mode"] = None |
| |
| user_credits_db[str_chat_id]["used_referral"] = True |
| user_credits_db[str_chat_id]["tts"] = user_credits_db[str_chat_id].get("tts", 0) + 10 |
| |
| user_credits_db[inviter_id]["invited_count"] = user_credits_db[inviter_id].get("invited_count", 0) + 1 |
| current_invites = user_credits_db[inviter_id]["invited_count"] |
| |
| if current_invites > 0 and current_invites % 10 == 0: |
| inviter_data = user_credits_db[inviter_id] |
| inviter_data["is_premium"] = True |
| now = datetime.datetime.now() |
| if inviter_data.get("expire_date"): |
| try: |
| current_exp = datetime.datetime.fromisoformat(inviter_data["expire_date"]) |
| if current_exp > now: |
| new_exp = current_exp + datetime.timedelta(days=3) |
| else: |
| new_exp = now + datetime.timedelta(days=3) |
| except: |
| new_exp = now + datetime.timedelta(days=3) |
| else: |
| new_exp = now + datetime.timedelta(days=3) |
| |
| inviter_data["expire_date"] = new_exp.isoformat() |
| inviter_data["chat"] = 999999 |
| inviter_data["image"] = 10 |
| inviter_data["edit_image"] = 5 |
| inviter_data["podcast"] = 999999 |
| inviter_data["tts"] = 999999 |
| inviter_data["file"] = 999999 |
| inviter_data["stt"] = 999999 |
| |
| save_db(user_credits_db) |
| try: |
| msg_text = f"🎉 **تبریک ویژه!**\nیک دوست کد هدیه شما را ثبت کرد.\nتعداد کل دعوتهای شما: {current_invites} نفر\n\n🎁 **هدیه شما:** ۳ روز اشتراک پرو نامحدود به حساب شما افزوده شد!" |
| asyncio.create_task(send_with_keyboard(client, inviter_id, msg_text, True)) |
| except: pass |
| else: |
| save_db(user_credits_db) |
| remains = 10 - (current_invites % 10) |
| try: |
| msg_text = f"🎉 **تبریک!**\nیک دوست کد هدیه شما را ثبت کرد.\nتعداد کل دعوتهای شما: {current_invites} نفر\n\n⏳ با دعوت {remains} نفر دیگر، ۳ روز اشتراک رایگان دریافت میکنید!" |
| asyncio.create_task(send_with_keyboard(client, inviter_id, msg_text, True)) |
| except: pass |
|
|
| await send_with_keyboard(client, chat_id, "✅ کد هدیه با موفقیت ثبت شد!\n🎁 **10 سهمیه تبدیل رایگان متن به صدا** به حساب شما اضافه گردید.", True) |
| return |
|
|
| elif current_mode == "chat": |
| if is_file: |
| await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False) |
| try: |
| file_bytes = await helper_download_file(client, msg_obj) |
| user_states[str_chat_id]["file_bytes"] = file_bytes |
| user_states[str_chat_id]["file_name"] = file_name |
| user_states[str_chat_id]["mode"] = "chat_waiting_for_prompt" |
| await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بفرستید و بگویید **چه کاری با این فایل انجام دهم؟**\n(مثلاً: این تصویر را توصیف کن، یا متن این سند را خلاصه کن)", False) |
| except Exception as dl_err: |
| await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False) |
| elif user_text_str: |
| asyncio.create_task(process_gemini(client, chat_id, user_text_str)) |
| return |
|
|
| elif current_mode == "chat_waiting_for_prompt": |
| if user_text_str: |
| saved_bytes = user_states[str_chat_id].get("file_bytes") |
| saved_name = user_states[str_chat_id].get("file_name", "file.jpeg") |
| user_states[str_chat_id]["mode"] = "chat" |
| user_states[str_chat_id]["file_bytes"] = None |
| asyncio.create_task(process_gemini(client, chat_id, user_text_str, file_bytes=saved_bytes, file_name=saved_name)) |
| else: |
| await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False) |
| return |
|
|
| elif current_mode == "image_waiting_for_text": |
| if user_text_str: |
| user_states[str_chat_id]["text"] = user_text_str |
| user_states[str_chat_id]["mode"] = "image_waiting_for_size" |
| |
| size_menu = """🖼 **لطفاً ابعاد تصویر خود را انتخاب کنید:** |
| |
| 1️⃣ `1:1` (مربع) - مناسب پروفایل ⬛ |
| 2️⃣ `9:16` (عمودی) - مناسب استوری و پسزمینه گوشی 📱 |
| 3️⃣ `16:9` (افقی) - مناسب دسکتاپ و ویدیو 🖥️ |
| 4️⃣ `4:3` (استاندارد) - مناسب چاپ و پست 📸 |
| |
| (لطفاً فقط عدد 1 تا 4 را بفرستید)""" |
| await send_with_keyboard(client, chat_id, size_menu, False) |
| else: |
| await send_with_keyboard(client, chat_id, "⚠️ لطفاً ایده عکس خود را به صورت متنی بفرستید.", False) |
| return |
|
|
| elif current_mode == "image_waiting_for_size": |
| normalized_choice = to_english_digits(user_text_str).strip() |
| if normalized_choice in["1", "2", "3", "4"]: |
| saved_text = user_states[str_chat_id].get("text", "") |
| user_states[str_chat_id]["mode"] = None |
| asyncio.create_task(process_image(client, chat_id, saved_text, normalized_choice)) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ عدد وارد شده نامعتبر است! لطفاً فقط یکی از اعداد 1 تا 4 را بفرستید.", False) |
| return |
|
|
| elif current_mode == "image_edit_waiting_for_image": |
| if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک عکس ارسال کنید.", False) |
| await send_with_keyboard(client, chat_id, "📥 در حال دانلود عکس...", False) |
| try: |
| file_bytes = await helper_download_file(client, msg_obj) |
| user_states[str_chat_id]["file_bytes"] = file_bytes |
| user_states[str_chat_id]["mode"] = "image_edit_waiting_for_prompt" |
| await send_with_keyboard(client, chat_id, "✅ عکس با موفقیت دریافت شد.\n\nحالا دستور خود را به صورت متنی تایپ کنید.\nمثال: یک کلاه قرمز روی سر این گربه بگذار.", False) |
| except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت عکس!\n{str(dl_err)}", False) |
| return |
|
|
| elif current_mode == "image_edit_waiting_for_prompt": |
| if user_text_str: |
| saved_bytes = user_states[str_chat_id].get("file_bytes") |
| user_states[str_chat_id]["mode"] = None |
| user_states[str_chat_id]["file_bytes"] = None |
| asyncio.create_task(process_image_edit(client, chat_id, saved_bytes, user_text_str)) |
| else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False) |
| return |
|
|
| elif current_mode == "tts_waiting_for_text": |
| if user_text_str: |
| if len(user_text_str) > 2500: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً متنی کوتاهتر از 2500 کاراکتر بفرستید.", False) |
| user_states[str_chat_id]["text"] = user_text_str |
| user_states[str_chat_id]["mode"] = "tts_waiting_for_speaker" |
| |
| speakers_menu = """✅ متن شما ذخیره شد. |
| لطفاً **شماره** گوینده مورد نظر خود را بفرستید: |
| 1. شهاب | 2. آوا | 3. نوید |
| 4. آرمان | 5. مهسا | 6. دانا |
| 7. سامان | 8. آرش | 9. شبنم |
| 10. سحر | 11. مریم | 12. بهرام |
| 13. نیکان| 14. فرناز | 15. سارا |
| 16. مانی | 17. آرتین | 18. دلنواز |
| 19. روژان | 20. امید | 21. بردیا |
| 22. ترانه | 23. نیکو | 24. هستی |
| 25. کامیار| 26. کیانوش| 27. پویا |
| 28. مهتاب | 29. سام | 30. لیدا""" |
| await send_with_keyboard(client, chat_id, speakers_menu, False) |
| return |
|
|
| elif current_mode == "tts_waiting_for_speaker": |
| normalized_text = to_english_digits(user_text_str) |
| |
| if normalized_text.isdigit() and normalized_text in SPEAKERS: |
| spk_name, spk_id = SPEAKERS[normalized_text] |
| txt = user_states[str_chat_id]["text"] |
| user_states[str_chat_id]["mode"] = "tts_waiting_for_text" |
| asyncio.create_task(process_tts(client, chat_id, txt, spk_id, spk_name)) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False) |
| return |
|
|
| elif current_mode == "podcast_waiting_for_topic": |
| if user_text_str: asyncio.create_task(process_podcast(client, chat_id, user_text_str)) |
| else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع پادکست خود را به صورت متنی بفرستید.", False) |
| return |
|
|
| elif current_mode == "stt_waiting_for_audio": |
| if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً یک فایل ارسال کنید.", False) |
| await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False) |
| try: |
| audio_bytes = await helper_download_file(client, msg_obj) |
| asyncio.create_task(process_stt(client, chat_id, audio_bytes, file_name)) |
| except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دانلود فایل!\n{str(dl_err)}", False) |
| return |
|
|
| elif current_mode == "file_waiting_for_file": |
| if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک فایل ارسال کنید.", False) |
| await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False) |
| try: |
| file_bytes = await helper_download_file(client, msg_obj) |
| user_states[str_chat_id]["file_bytes"] = file_bytes |
| user_states[str_chat_id]["file_name"] = file_name |
| user_states[str_chat_id]["mode"] = "file_waiting_for_prompt" |
| await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بگویید **چگونه تحلیل شود؟**\n(میتوانید سوال خاصی بپرسید یا فقط بخواهید فایل را توضیح دهد)", False) |
| except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False) |
| return |
|
|
| elif current_mode == "file_waiting_for_prompt": |
| if user_text_str: |
| saved_bytes = user_states[str_chat_id].get("file_bytes") |
| saved_name = user_states[str_chat_id].get("file_name", "file.jpeg") |
| user_states[str_chat_id]["mode"] = "file_waiting_for_file" |
| asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str)) |
| else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False) |
| return |
|
|
| elif current_mode == "create_file_waiting_for_topic": |
| if user_text_str: |
| asyncio.create_task(process_create_file(client, chat_id, user_text_str)) |
| else: |
| await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع مقاله خود را به صورت متنی بفرستید.", False) |
| return |
|
|
| elif current_mode == "vc_waiting_for_voice": |
| if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً یک فایل صوتی یا ویس ارسال کنید.", False) |
| await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل صوتی شما...", False) |
| try: |
| file_bytes = await helper_download_file(client, msg_obj) |
| user_states[str_chat_id]["file_bytes"] = file_bytes |
| user_states[str_chat_id]["mode"] = "vc_waiting_for_model" |
| |
| model_menu = "✅ صدای شما دریافت شد.\n\nلطفا **شماره** مدلی که میخواهید صدایتان به آن تبدیل شود را ارسال کنید:\n\n" |
| for k, v in LEGACY_MODELS.items(): |
| if k == "8": |
| model_menu += f"{k}. {v['name']} (نامحدود رایگان)\n" |
| else: |
| model_menu += f"{k}. {v['name']}\n" |
| model_menu += "➖➖➖➖➖➖➖➖\n" |
| for k, v in STANDARD_MODELS.items(): model_menu += f"{k}. {v['name']}\n" |
| |
| await send_with_keyboard(client, chat_id, model_menu, False) |
| except Exception as dl_err: |
| await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False) |
| return |
|
|
| elif current_mode == "vc_waiting_for_model": |
| choice = to_english_digits(user_text_str).strip() |
| |
| if choice in STANDARD_MODELS: |
| if creds["voice_conv"] <= 0: return await send_with_keyboard(client, chat_id, "❌ سهمیه تغییر صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
| user_states[str_chat_id]["mode"] = None |
| model = STANDARD_MODELS[choice] |
| src_bytes = user_states[str_chat_id]["file_bytes"] |
| await send_with_keyboard(client, chat_id, "📥 در حال آمادهسازی فایلها...", False) |
| ref_bytes = await helper_download_url_to_bytes(model["ref"]) |
| if not ref_bytes: return await send_with_keyboard(client, chat_id, "❌ خطا در دسترسی به فایل صدای مدل.", False) |
| |
| asyncio.create_task(process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, model["name"], "voice_conv")) |
| |
| elif choice in LEGACY_MODELS: |
| if choice != "8" and creds["voice_conv"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ سهمیه تغییر صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False) |
| |
| user_states[str_chat_id]["selected_model"] = choice |
| user_states[str_chat_id]["mode"] = "vc_waiting_for_gender" |
| |
| gender_msg = f"✅ مدل {LEGACY_MODELS[choice]['name']} انتخاب شد.\n\nبرای تنظیم دقیق فرکانسها به ما بگویید صدایی که خودتان فرستادید صدای یک **مرد** است یا **زن**؟\n\n1. مرد 👨\n2. زن 👩" |
| await send_with_keyboard(client, chat_id, gender_msg, False) |
| else: |
| await send_with_keyboard(client, chat_id, "❌ شماره وارد شده صحیح نیست. لطفاً فقط عدد مدل را بفرستید.", False) |
| return |
|
|
| elif current_mode == "vc_waiting_for_gender": |
| choice = to_english_digits(user_text_str).strip() |
| if choice not in["1", "2"]: |
| return await send_with_keyboard(client, chat_id, "❌ لطفاً عدد 1 (مرد) یا 2 (زن) را ارسال کنید.", False) |
| |
| user_gender = "male" if choice == "1" else "female" |
| model_key = user_states[str_chat_id]["selected_model"] |
| model = LEGACY_MODELS[model_key] |
| target_gender = model["gender"] |
| |
| pitch = 0 |
| if target_gender == "female" and user_gender == "male": pitch = 12 |
| elif target_gender == "male" and user_gender == "female": pitch = -12 |
| |
| user_states[str_chat_id]["mode"] = None |
| src_bytes = user_states[str_chat_id]["file_bytes"] |
| asyncio.create_task(process_legacy_vc_job(client, chat_id, src_bytes, model["url"], pitch, model["name"])) |
| return |
|
|
| elif current_mode == "clone_waiting_for_src": |
| if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً فایل صوتی صدای خودتان را بفرستید.", False) |
| await send_with_keyboard(client, chat_id, "📥 در حال دانلود صدای شما...", False) |
| try: |
| file_bytes = await helper_download_file(client, msg_obj) |
| user_states[str_chat_id]["file_bytes"] = file_bytes |
| user_states[str_chat_id]["mode"] = "clone_waiting_for_ref" |
| await send_with_keyboard(client, chat_id, "✅ صدای شما دریافت شد.\n\nحالا **فایل الگو (صدای شخصی که میخواهید شبیهسازی کنید)** را ارسال کنید.\n(پیشنهاد: فایل بدون نویز و موسیقی، بین ۳ تا ۱۰ ثانیه)", False) |
| except Exception as dl_err: |
| await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False) |
| return |
|
|
| elif current_mode == "clone_waiting_for_ref": |
| if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً فایل صوتی الگوی هدف را بفرستید.", False) |
| await send_with_keyboard(client, chat_id, "📥 در حال دانلود صدای الگو...", False) |
| try: |
| ref_bytes = await helper_download_file(client, msg_obj) |
| |
| if creds["voice_clone"] <= 0: |
| return await send_with_keyboard(client, chat_id, "❌ سهمیه کلون کردن صدای شما تمام شده است. نیازمند تهیه اشتراک هستید.", False) |
| |
| user_states[str_chat_id]["mode"] = None |
| src_bytes = user_states[str_chat_id]["file_bytes"] |
| |
| asyncio.create_task(process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, "صدای اختصاصی (کلون شده)", "voice_clone")) |
| except Exception as dl_err: |
| await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False) |
| return |
|
|
| except Exception: traceback.print_exc() |
|
|
| if __name__ == "__main__": |
| threading.Thread(target=run_flask, daemon=True).start() |
| |
| if bot_token: |
| loop = asyncio.get_event_loop() |
| |
| loop.set_default_executor(concurrent.futures.ThreadPoolExecutor(max_workers=256)) |
| |
| loop.create_task(ram_garbage_collector()) |
| |
| print("🚀 ربات آلفا پرو (نسخه صنعتی + دیتابیس هوشمند + فیلتر زمان قطعی + 256 تونل همزمان) روشن شد...") |
| bot.run() |