Opera8 commited on
Commit
d8191da
·
verified ·
1 Parent(s): c8aec50

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +218 -137
main.py CHANGED
@@ -79,7 +79,6 @@ def load_db():
79
  print("در حال تلاش برای خواندن دیتابیس کاربران از دیتاست هاگینگ فیس...")
80
  if HF_TOKEN_DB:
81
  try:
82
- # دانلود دیتابیس از دیتاست خصوصی
83
  file_path = hf_hub_download(
84
  repo_id=DATASET_REPO,
85
  filename=DB_FILE,
@@ -90,9 +89,8 @@ def load_db():
90
  print("✅ دیتابیس با موفقیت از دیتاست هاگینگ فیس لود شد.")
91
  return json.load(f)
92
  except Exception as e:
93
- print("⚠️ فایل دیتابیس در هاگینگ فیس یافت نشد یا خطایی رخ داد (ساخت دیتابیس جدید). جزئیات:", str(e)[:100])
94
 
95
- # اگر از دیتاست لود نشد، از لوکال بخوان
96
  if os.path.exists(DB_FILE):
97
  try:
98
  with open(DB_FILE, "r", encoding="utf-8") as f:
@@ -102,7 +100,6 @@ def load_db():
102
  return {}
103
 
104
  def _upload_db_background():
105
- """تابع کمکی برای آپلود دیتابیس بدون درگیر کردن سرعت ربات"""
106
  if HF_TOKEN_DB:
107
  api = HfApi(token=HF_TOKEN_DB)
108
  try:
@@ -118,24 +115,40 @@ def _upload_db_background():
118
  def save_db(db_data):
119
  with db_lock:
120
  try:
121
- # ذخیره فایل به صورت لوکال
122
  with open(DB_FILE, "w", encoding="utf-8") as f:
123
  json.dump(db_data, f, ensure_ascii=False, indent=4)
124
-
125
- # استارت کردن یک Thread جدید برای آپلود به دیتاست تا ربات منتظر نماند
126
  threading.Thread(target=_upload_db_background, daemon=True).start()
127
  except Exception as e:
128
  print("خطا در ذخیره دیتابیس:", e)
129
 
130
  user_credits_db = load_db()
131
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  def get_user_credits(chat_id):
133
- # اطمینان از پاک بودن استرینگ از علائم مزاحم
134
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
135
  today_str = datetime.date.today().isoformat()
136
 
137
  if str_chat_id not in user_credits_db:
138
- # ساخت کاربر جدید با مقادیر اولیه
139
  user_credits_db[str_chat_id] = {
140
  "is_premium": False,
141
  "expire_date": None,
@@ -147,30 +160,29 @@ def get_user_credits(chat_id):
147
  "tts": 5,
148
  "file": 1,
149
  "stt": 5,
150
- "has_joined": False
 
 
 
151
  }
152
  save_db(user_credits_db)
153
 
154
  user_data = user_credits_db[str_chat_id]
155
  is_premium = user_data.get("is_premium", False)
156
 
157
- # 🛡 بررسی انقضای اشتراک ماهانه کاربران ویژه 🛡
158
  if is_premium and user_data.get("expire_date"):
159
  try:
160
  expire_date = datetime.datetime.fromisoformat(user_data["expire_date"])
161
  if datetime.datetime.now() > expire_date:
162
- # اگر زمان اشتراک تمام شده باشد، دوباره رایگان می‌شود
163
  user_data["is_premium"] = False
164
  user_data["expire_date"] = None
165
  is_premium = False
166
  except Exception:
167
  pass
168
 
169
- # 🔄 سیستم شارژ روزانه (فقط و فقط برای نسخه رایگان) 🔄
170
  if not is_premium:
171
  if user_data.get("last_reset") != today_str:
172
  user_data["last_reset"] = today_str
173
- # شارژ روزانه نسخه رایگان
174
  user_data["chat"] = 10
175
  user_data["image"] = 5
176
  user_data["edit_image"] = 1
@@ -197,7 +209,7 @@ app = Flask(__name__)
197
 
198
  @app.route('/')
199
  def home():
200
- return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دیتاست + سیستم ضد باگ) روشن است! 🚀"
201
 
202
  def run_flask():
203
  app.run(host="0.0.0.0", port=7860)
@@ -240,6 +252,12 @@ MAIN_KEYPAD_DICT = {
240
  {"id": "buy_btn", "type": "Simple", "button_text": "خرید اشتراک 💎"}
241
  ]
242
  },
 
 
 
 
 
 
243
  {
244
  "buttons":[
245
  {"id": "transfer_btn", "type": "Simple", "button_text": "انتقال اکانت از برنامه به ربات"}
@@ -254,7 +272,6 @@ MAIN_KEYPAD_DICT = {
254
  "resize_keyboard": True
255
  }
256
 
257
- # --- ⛔️ سیستم بررسی عضویت اجباری کانال (Force Join) ⛔️ ---
258
  CHANNEL_USERNAME = "aialpha"
259
  CHANNEL_GUID = None
260
 
@@ -271,7 +288,6 @@ JOIN_KEYPAD_DICT = {
271
 
272
  async def check_channel_membership(client, user_id):
273
  global CHANNEL_GUID
274
- # جلوگیری از بلاک شدن خود ربات
275
  if str(user_id) == str(BOT_GUID): return True
276
 
277
  try:
@@ -293,7 +309,7 @@ async def check_channel_membership(client, user_id):
293
  CHANNEL_GUID = getattr(res.exist.chat, 'object_guid', None)
294
 
295
  if not CHANNEL_GUID:
296
- return True # در صورت عدم یافتن آیدی کانال، اجازه عبور داده می‌شود
297
 
298
  payload = {
299
  "channel_guid": CHANNEL_GUID,
@@ -312,10 +328,9 @@ async def check_channel_membership(client, user_id):
312
 
313
  return False
314
  except Exception:
315
- return False # فرض بر این است که عضو نیست
316
 
317
 
318
- # --- تابع ارسال منحصراً برای کیبورد پایین صفحه ---
319
  async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
320
  try:
321
  if not use_keyboard:
@@ -335,7 +350,6 @@ async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
335
  return None
336
 
337
 
338
- # --- 🚨 تابع هوشمند دانلود فایل (با استفاده از UUID جهت جلوگیری از تداخل حریم خصوصی) 🚨 ---
339
  async def helper_download_file(client, msg_obj):
340
  errors =[]
341
  file_id = None
@@ -348,7 +362,6 @@ async def helper_download_file(client, msg_obj):
348
  elif isinstance(val, dict) and 'file_id' in val: file_id = val['file_id']
349
  if file_id: break
350
 
351
- # 🛡 استفاده از UUID به جای اعداد تصادفی برای تضمین ۱۰۰ درصدی عدم تداخل نام فایل‌ها 🛡
352
  temp_name = f"temp_dl_{uuid.uuid4().hex}.tmp"
353
 
354
  if hasattr(client, "download_file"):
@@ -389,7 +402,6 @@ async def helper_download_file(client, msg_obj):
389
  raise Exception("دانلود ناموفق. لاگ:\n" + "\n".join(errors))
390
 
391
 
392
- # --- تنظیمات کلیدها ---
393
  GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "")
394
  GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "")
395
 
@@ -399,21 +411,13 @@ if GEMINI_KEYS_STR1:
399
  if GEMINI_KEYS_STR2:
400
  _raw_keys.extend(GEMINI_KEYS_STR2.split(","))
401
 
402
- # حذف کلیدهای تکراری و خالی
403
  GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()]))
404
  print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.")
405
 
406
- # --- 🚀 سیستم چرخشی پیشرفته (Round-Robin) برای کلیدهای جیمینای ---
407
  current_gemini_key_index = 0
408
  gemini_key_lock = threading.Lock()
409
 
410
  def get_next_gemini_keys(count=100):
411
- """
412
- این تابع تضمین می‌کند که به ترتیب از کلیدها استفاده شود.
413
- مثلاً درخواست اول کلیدهای ۱ تا ۱۰۰ را می‌گیرد.
414
- درخواست دوم کلیدهای ۱۰۱ تا ۲۰۰ را می‌گیرد.
415
- و وقتی به آخر لیست برسد، دوباره از اول شروع می‌کند.
416
- """
417
  global current_gemini_key_index
418
  with gemini_key_lock:
419
  total_keys = len(GEMINI_KEYS)
@@ -435,25 +439,21 @@ HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
435
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
436
 
437
 
438
- # --- 🚨 تابع اختصاصی آپلود فایل به روبیکا (مجهز به سیستم Fallback هوشمند صوتی و Music) 🚨 ---
439
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
440
  abs_path = os.path.abspath(file_name)
441
  error_logs =[]
442
 
443
  api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in["voice", "Voice", "audio"] else "File"
444
 
445
- # اگر قرار است ویس ارسال شود اما فایل پسوند مناسب ندارد، برای جلوگیری از ارور فوراً به Music تبدیل می‌کنیم
446
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
447
  api_file_type = "Music"
448
 
449
- # سیستم ۳ بار تلاش مجدد برای جلوگیری از قطعی سرور روبیکا
450
  for attempt in range(3):
451
  try:
452
  url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
453
  url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
454
 
455
  async with aiohttp.ClientSession() as session:
456
- # ۱. درخواست آدرس آپلود از روبیکا
457
  async with session.post(url_request, json={"type": api_file_type}, timeout=20) as resp:
458
  if resp.status != 200:
459
  error_logs.append(f"Request HTTP {resp.status}")
@@ -465,17 +465,14 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
465
  if req_data.get("status") == "OK":
466
  upload_url = req_data.get("data", {}).get("upload_url")
467
 
468
- # اگر آدرس آپلود با موفقیت دریافت شد
469
  if upload_url:
470
  with open(abs_path, "rb") as f:
471
  form = aiohttp.FormData()
472
  form.add_field('file', f, filename=os.path.basename(abs_path))
473
 
474
- # ۲. ارسال فایل به لینک آپلود
475
  async with session.post(upload_url, data=form, timeout=60) as up_resp:
476
  if up_resp.status != 200:
477
  error_logs.append(f"Upload HTTP {up_resp.status}")
478
- # 🔴 اگر ارور 502 داد یعنی روبیکا فرمت ویس را پس زده است، پس تبدیل به حالت Music می‌کنیم
479
  if up_resp.status == 502 and api_file_type == "Voice":
480
  api_file_type = "Music"
481
  await asyncio.sleep(1.5)
@@ -488,7 +485,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
488
  await asyncio.sleep(1.5)
489
  continue
490
 
491
- # ۳. گرفتن file_id از پاسخی که سرور آپلود برمی‌گرداند
492
  final_file_id = None
493
  if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
494
  if "data" in up_data and isinstance(up_data["data"], dict):
@@ -497,7 +493,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
497
  final_file_id = up_data.get("file_id")
498
 
499
  if final_file_id:
500
- # ۴. ارسال نهایی پیام
501
  send_payload = {
502
  "chat_id": str(chat_id),
503
  "file_id": str(final_file_id),
@@ -517,7 +512,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
517
  else:
518
  error_logs.append(f"SendFile API Error: {s_data}")
519
  else:
520
- # 🔴 اگر فرمت فایل نامعتبر بود، به جای ویس، به صورت موزیک (دارای دکمه پخش) ارسال کن
521
  if up_data.get("status") == "INVALID_INPUT" and api_file_type == "Voice":
522
  api_file_type = "Music"
523
  error_logs.append(f"Upload API Error: {up_data}")
@@ -529,7 +523,6 @@ async def helper_upload_file(client, chat_id, file_name, file_type="Image", capt
529
  error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
530
  await asyncio.sleep(1.5)
531
 
532
- # تلاش نهایی از طریق روب‌پای به عنوان راه جایگزین
533
  try:
534
  if hasattr(client, "send_file"):
535
  await client.send_file(chat_id, abs_path)
@@ -567,7 +560,6 @@ processed_message_ids = set()
567
  user_last_request_time = {}
568
 
569
 
570
- # --- ۱. پردازش چت متنی و چندرسانه‌ای ---
571
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
572
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
573
  creds = get_user_credits(str_chat_id)
@@ -604,7 +596,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
604
  history = history[-40:]
605
  if history[0]["role"] == "model": history = history[1:]
606
 
607
- # دریافت ۱۰۰ کلید به صورت چرخشی
608
  keys_to_try = get_next_gemini_keys(100)
609
  final_answer = None
610
 
@@ -622,7 +613,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
622
  except (KeyError, IndexError): continue
623
  except Exception: continue
624
 
625
- # --- Fallback to Hugging Face Gemma 4 ---
626
  if not final_answer and HF_TOKENS:
627
  hf_messages =[]
628
  for msg in history:
@@ -673,7 +663,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
673
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", False)
674
  return
675
 
676
- # کسر اعتبار در دیتاست (اگر نامحدود نیست)
677
  if not creds.get("is_premium"):
678
  user_credits_db[str_chat_id]["chat"] -= 1
679
  save_db(user_credits_db)
@@ -704,7 +693,6 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
704
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
705
 
706
 
707
- # --- ۲. پردازش ساخت عکس ---
708
  async def process_image(client, chat_id, prompt):
709
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
710
  creds = get_user_credits(str_chat_id)
@@ -718,7 +706,6 @@ async def process_image(client, chat_id, prompt):
718
  gemini_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}"
719
 
720
  if GEMINI_KEYS:
721
- # دریافت ۱۰۰ کلید به صورت چرخشی
722
  keys_to_try_gemini = get_next_gemini_keys(100)
723
  async with aiohttp.ClientSession() as session:
724
  for key in keys_to_try_gemini:
@@ -732,7 +719,6 @@ async def process_image(client, chat_id, prompt):
732
  break
733
  except Exception: continue
734
 
735
- # Fallback to HF Router if Gemini fails
736
  if enhanced_prompt == prompt and HF_TOKENS:
737
  keys_to_try_hf = HF_TOKENS.copy()
738
  random.shuffle(keys_to_try_hf)
@@ -758,7 +744,7 @@ async def process_image(client, chat_id, prompt):
758
  if proc_msg:
759
  msg_id = getattr(proc_msg, 'message_id', None)
760
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
761
- if msg_id: await client.delete_messages(chat_id, [msg_id])
762
  except Exception: pass
763
 
764
  short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
@@ -787,7 +773,6 @@ async def process_image(client, chat_id, prompt):
787
 
788
  if not generated_image: return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
789
 
790
- # کسر اعتبار (ساخت عکس محدود است حتی برای پرو)
791
  user_credits_db[str_chat_id]["image"] -= 1
792
  save_db(user_credits_db)
793
 
@@ -802,7 +787,7 @@ async def process_image(client, chat_id, prompt):
802
  if os.path.exists(file_name): os.remove(file_name)
803
  except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
804
 
805
- # --- تابع جدید برای ارسال متن به اسپیس مترجم ---
806
  async def translate_text_aloha(prompt_text):
807
  session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
808
  join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join"
@@ -814,12 +799,10 @@ async def translate_text_aloha(prompt_text):
814
 
815
  try:
816
  async with aiohttp.ClientSession() as session:
817
- # پیوستن به صف ترجمه
818
  async with session.post(join_url, json=payload, timeout=20) as resp:
819
  if resp.status != 200:
820
  return prompt_text
821
 
822
- # دریافت داده‌ها به صورت جریانی (Stream)
823
  data_url = f"https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/data?session_hash={session_hash}"
824
  async with session.get(data_url, timeout=60) as resp:
825
  async for line_bytes in resp.content:
@@ -838,7 +821,7 @@ async def translate_text_aloha(prompt_text):
838
 
839
  return prompt_text
840
 
841
- # --- ۲.۵. پردازش ویرایش عکس با FLUX.2-dev ---
842
  async def process_image_edit(client, chat_id, image_bytes, prompt):
843
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
844
  creds = get_user_credits(str_chat_id)
@@ -850,7 +833,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
850
 
851
  proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال ترجمه دستور شما توسط اسپیس و اعمال جادوی FLUX.2...\n(این فرآیند ممکن است کمی طول بکشد)", False)
852
 
853
- # گرفتن ترجمه از اسپیس درخواستی
854
  translated_prompt = await translate_text_aloha(prompt)
855
  if not translated_prompt or translated_prompt.strip() == "":
856
  translated_prompt = prompt
@@ -883,7 +865,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
883
  if not generated_image:
884
  return await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
885
 
886
- # کسر اعتبار (ویرایش عکس محدود است حتی برای پرو)
887
  user_credits_db[str_chat_id]["edit_image"] -= 1
888
  save_db(user_credits_db)
889
 
@@ -901,7 +882,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
901
  await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
902
 
903
 
904
- # --- ۳. پردازش ساخت صدا ---
905
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
906
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
907
  creds = get_user_credits(str_chat_id)
@@ -938,19 +918,15 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
938
  except Exception: pass
939
 
940
  if audio_bytes:
941
- # کسر اعتبار در دیتاست (اگر نامحدود نیست)
942
  if not creds.get("is_premium"):
943
  user_credits_db[str_chat_id]["tts"] -= 1
944
  save_db(user_credits_db)
945
 
946
- # فایل صوتی را فقط به صورت MP3 ذخیره می‌کنیم تا از مشکل 502 روبیکا جلوگیری شود
947
  file_name_mp3 = f"audio_{uuid.uuid4().hex}.mp3"
948
 
949
  with open(file_name_mp3, "wb") as f: f.write(audio_bytes)
950
 
951
  await asyncio.sleep(1)
952
-
953
- # ارسال فقط به صورت فایل دانلودشونده MP3 (حالت Voice حذف شد)
954
  upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
955
 
956
  if upload_result_file is not True:
@@ -961,7 +937,6 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
961
  except Exception: traceback.print_exc()
962
 
963
 
964
- # --- ۳.۵. پردازش پادکست ---
965
  async def process_podcast(client, chat_id, prompt):
966
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
967
  creds = get_user_credits(str_chat_id)
@@ -1031,12 +1006,10 @@ async def process_podcast(client, chat_id, prompt):
1031
  combined_audio += audio_segment
1032
  except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا (آیا pydub و ffmpeg نصب است؟):\n{str(e)}", True)
1033
 
1034
- # کسر اعتبار در دیتاست (اگر نامحدود نیست)
1035
  if not creds.get("is_premium"):
1036
  user_credits_db[str_chat_id]["podcast"] -= 1
1037
  save_db(user_credits_db)
1038
 
1039
- # فقط با فرمت MP3 خروجی می‌دهیم (بدون تبدیل OGG)
1040
  file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
1041
  combined_audio.export(file_name_mp3, format="mp3")
1042
 
@@ -1048,8 +1021,6 @@ async def process_podcast(client, chat_id, prompt):
1048
  except: pass
1049
 
1050
  caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
1051
-
1052
- # ارسال فقط به صورت فایل MP3
1053
  upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", caption_file)
1054
 
1055
  if upload_result_file is not True:
@@ -1058,7 +1029,6 @@ async def process_podcast(client, chat_id, prompt):
1058
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1059
 
1060
 
1061
- # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
1062
  async def process_stt(client, chat_id, audio_bytes, file_name):
1063
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1064
  creds = get_user_credits(str_chat_id)
@@ -1072,7 +1042,6 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
1072
  mime_type, _ = mimetypes.guess_type(file_name)
1073
  if not mime_type: mime_type = "audio/ogg"
1074
 
1075
- # دریافت ۱۰۰ کلید به صورت چرخشی
1076
  keys_to_try = get_next_gemini_keys(100)
1077
  transcribed_text = None
1078
  prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
@@ -1080,7 +1049,7 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
1080
  async with aiohttp.ClientSession() as session:
1081
  for key in keys_to_try:
1082
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1083
- payload = {"contents": [{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.2}}
1084
  try:
1085
  async with session.post(url, json=payload, timeout=60) as response:
1086
  if response.status == 200:
@@ -1097,7 +1066,6 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
1097
  except Exception: pass
1098
 
1099
  if transcribed_text:
1100
- # کسر اعتبار در دیتاست (اگر نامحدود نیست)
1101
  if not creds.get("is_premium"):
1102
  user_credits_db[str_chat_id]["stt"] -= 1
1103
  save_db(user_credits_db)
@@ -1106,7 +1074,6 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
1106
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1107
 
1108
 
1109
- # --- ۵. پردازش تحلیل فایل مستقل ---
1110
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1111
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1112
  creds = get_user_credits(str_chat_id)
@@ -1120,14 +1087,13 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1120
  mime_type, _ = mimetypes.guess_type(file_name)
1121
  if not mime_type: mime_type = "image/jpeg"
1122
 
1123
- # دریافت ۱۰۰ کلید به صورت چرخشی
1124
  keys_to_try = get_next_gemini_keys(100)
1125
  final_answer = None
1126
 
1127
  async with aiohttp.ClientSession() as session:
1128
  for key in keys_to_try:
1129
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1130
- payload = {"contents": [{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.6}}
1131
  try:
1132
  async with session.post(url, json=payload, timeout=45) as response:
1133
  if response.status == 200:
@@ -1144,7 +1110,6 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1144
  except Exception: pass
1145
 
1146
  if final_answer:
1147
- # کسر اعتبار در دیتاست (اگر نامحدود نیست)
1148
  if not creds.get("is_premium"):
1149
  user_credits_db[str_chat_id]["file"] -= 1
1150
  save_db(user_credits_db)
@@ -1153,12 +1118,10 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1153
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1154
 
1155
 
1156
- # --- ۵.۵. پردازش ساخت مقاله و تبدیل به فایل (PDF & DOCX) ---
1157
  async def process_create_file(client, chat_id, topic):
1158
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1159
  creds = get_user_credits(str_chat_id)
1160
 
1161
- # بررسی محدودیت بخش ساخت فایل (کسر از اعتبار پیام چت)
1162
  if creds["chat"] <= 0:
1163
  return await send_with_keyboard(client, chat_id, "❌ اعتبار چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1164
 
@@ -1182,7 +1145,6 @@ async def process_create_file(client, chat_id, topic):
1182
  break
1183
  except Exception: continue
1184
 
1185
- # Fallback to Hugging Face
1186
  if not article_text and HF_TOKENS:
1187
  keys_to_try_hf = HF_TOKENS.copy()
1188
  random.shuffle(keys_to_try_hf)
@@ -1220,7 +1182,6 @@ async def process_create_file(client, chat_id, topic):
1220
  converter_url = "https://opera8-texttopdf.hf.space/"
1221
 
1222
  async with aiohttp.ClientSession() as session:
1223
- # دریافت خروجی PDF
1224
  try:
1225
  form_data_pdf = aiohttp.FormData()
1226
  form_data_pdf.add_field('content', article_text)
@@ -1230,7 +1191,6 @@ async def process_create_file(client, chat_id, topic):
1230
  pdf_bytes = await resp.read()
1231
  except Exception as e: print("PDF creation error:", e)
1232
 
1233
- # دریافت خروجی DOCX
1234
  try:
1235
  form_data_docx = aiohttp.FormData()
1236
  form_data_docx.add_field('content', article_text)
@@ -1250,7 +1210,6 @@ async def process_create_file(client, chat_id, topic):
1250
  if not pdf_bytes and not docx_bytes:
1251
  return await send_with_keyboard(client, chat_id, "❌ متاسفانه در تبدیل متن به فایل خطایی رخ داد.", True)
1252
 
1253
- # کسر اعتبار ساخت فایل از سهمیه "چت" کاربر در صورت غیر پرمیوم بودن
1254
  if not creds.get("is_premium"):
1255
  user_credits_db[str_chat_id]["chat"] -= 1
1256
  save_db(user_credits_db)
@@ -1282,7 +1241,6 @@ async def process_create_file(client, chat_id, topic):
1282
  await send_with_keyboard(client, chat_id, "❌ فایل‌ها ساخته شدند اما روبیکا در ارسال آن‌ها دچار مشکل شد.", True)
1283
 
1284
 
1285
- # --- تنظیمات ربات روبیکا ---
1286
  if not bot_token:
1287
  print("خطا: توکن ربات روبیکا وارد نشده است!")
1288
  else:
@@ -1292,13 +1250,10 @@ else:
1292
  async def main_handler(client, update):
1293
  global BOT_GUID
1294
 
1295
- # 🔥 سیستم ضد رگبار و تخلیه صف (Backlog) سرور 🔥
1296
- # در صورت هجوم پیام‌های تلنبار شده سرور روبیکا، پیام‌ها رد می‌شود
1297
  if is_backlog_burst():
1298
  return
1299
 
1300
  try:
1301
- # 🛡 دریافت آیدی یکتای ربات برای جلوگیری از لوپ 🛡
1302
  if not BOT_GUID:
1303
  try:
1304
  me_info = await client.get_me()
@@ -1309,25 +1264,20 @@ else:
1309
 
1310
  msg_obj = getattr(update, "message", None) or getattr(update, "new_message", None)
1311
 
1312
- # --- استخراج دقیق شناسه فرستنده (برای جلوگیری از حرف زدن ربات با خودش) ---
1313
  author_id = getattr(update, 'author_guid', None)
1314
  if not author_id and msg_obj:
1315
  author_id = msg_obj.get('author_object_guid') if isinstance(msg_obj, dict) else getattr(msg_obj, 'author_object_guid', None)
1316
 
1317
- # ⛔️ حیاتی‌ترین بخش: اگر نویسنده پیام خودِ ربات است، هرگز پردازش نشود!
1318
  if BOT_GUID and author_id == BOT_GUID:
1319
  return
1320
 
1321
- # --- استخراج دقیق شناسه چت ---
1322
  chat_id = getattr(update, 'object_guid', None) or getattr(update, 'author_guid', None) or getattr(update, "chat_id", None)
1323
  if not chat_id: return
1324
 
1325
- # استخراج آیدی پیام
1326
  msg_id = getattr(update, "message_id", None)
1327
  if not msg_id and msg_obj:
1328
  msg_id = msg_obj.get("message_id") if isinstance(msg_obj, dict) else getattr(msg_obj, "message_id", None)
1329
 
1330
- # 🛡 کلید ترکیبی ضد تداخل: آیدی چت + آیدی پیام 🛡
1331
  unique_msg_key = f"{chat_id}_{msg_id}" if msg_id else None
1332
  if unique_msg_key:
1333
  if unique_msg_key in processed_message_ids: return
@@ -1336,21 +1286,22 @@ else:
1336
 
1337
  current_time = time.time()
1338
 
1339
- # 🛡 سیستم محدودکننده سرعت کاربر (Rate Limit) 🛡
1340
  last_req_time = user_last_request_time.get(chat_id, 0)
1341
  if current_time - last_req_time < 1.0:
1342
  return
1343
  user_last_request_time[chat_id] = current_time
1344
 
1345
- # تشخیص محتوای متنی
1346
  user_text = getattr(update, "text", "") or getattr(msg_obj, "text", "")
1347
  user_text_str = str(user_text).strip() if user_text else ""
1348
  user_text_lower = user_text_str.lower()
1349
 
1350
- if chat_id not in user_states:
1351
- user_states[chat_id] = {"mode": None, "text": "", "history":[], "file_bytes": None, "file_name": None}
 
 
 
 
1352
 
1353
- # 🛠 --- سیستم پنل مدیریت (بدون نیاز به لاگین) --- 🛠
1354
  if user_text_lower.startswith(f"{ADMIN_CODE} pro=") or user_text_lower.startswith(f"{ADMIN_CODE}pro="):
1355
  parts = user_text_str.split("=", 1)
1356
  if len(parts) >= 2:
@@ -1368,7 +1319,10 @@ else:
1368
  "tts": 5,
1369
  "file": 1,
1370
  "stt": 5,
1371
- "has_joined": True
 
 
 
1372
  }
1373
 
1374
  user_credits_db[target_id]["is_premium"] = True
@@ -1437,10 +1391,12 @@ else:
1437
  stt_rem = "نامحدود ∞" if is_prem else t_creds.get('stt', 0)
1438
  image_rem = t_creds.get('image', 0)
1439
  edit_image_rem = t_creds.get('edit_image', 0)
 
1440
 
1441
  info_msg = f"""🔍 **اطلاعات کاربر `{target_id}`:**
1442
 
1443
  🔹 **وضعیت:** {status_text}
 
1444
 
1445
  📊 **سهمیه:**
1446
  - چت: {chat_rem}
@@ -1455,7 +1411,6 @@ else:
1455
  await send_with_keyboard(client, chat_id, f"❌ کاربری با شناسه `{target_id}` در دیتابیس یافت نشد.", False)
1456
  return
1457
 
1458
- # تشخیص فایل
1459
  is_file = False
1460
  file_name = f"unknown_file_{uuid.uuid4().hex[:6]}.jpg"
1461
 
@@ -1476,13 +1431,8 @@ else:
1476
  file_name = file_attr.get('file_name', file_name) if isinstance(file_attr, dict) else file_name
1477
  break
1478
 
1479
- # ⛔️ سیستم قفل اجباری کانال (Force Join) - حالت اعتمادی (یک بار کلیک) ⛔️
1480
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1481
- creds = get_user_credits(str_chat_id)
1482
-
1483
  if user_text_str == "✅ عضو شدم":
1484
  if not creds.get("has_joined", False):
1485
- # با همان کلیک اول تایید می‌شود
1486
  user_credits_db[str_chat_id]["has_joined"] = True
1487
  save_db(user_credits_db)
1488
  await send_with_keyboard(client, chat_id, "🎉 **عضویت شما با موفقیت تایید شد! خیلی خوش آمدید.**\n\nحالا می‌توانید از تمامی امکانات ربات استفاده کنید.\nلطفاً یکی از گزینه‌های منو را انتخاب کنید:", True)
@@ -1500,15 +1450,19 @@ else:
1500
  await client.send_message(chat_id, join_msg)
1501
  return
1502
 
1503
- if user_text_str in["/start", "سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
1504
- user_states[chat_id]["mode"] = None
1505
- user_states[chat_id]["file_bytes"] = None
 
 
 
 
 
 
1506
  await send_with_keyboard(client, chat_id, "سلام! به ربات هوش مصنوعی آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
1507
  return
1508
 
1509
- # --- حساب کاربری ---
1510
  if user_text_str in["/account", "حساب کاربری 👤"]:
1511
- creds = get_user_credits(chat_id)
1512
  is_prem = creds.get("is_premium", False)
1513
 
1514
  if is_prem:
@@ -1538,11 +1492,15 @@ else:
1538
  stt_rem = "نامحدود ∞" if is_prem else creds['stt']
1539
  image_rem = creds['image']
1540
  edit_image_rem = creds['edit_image']
 
 
1541
 
1542
  account_profile = f"""👤 **اطلاعات حساب کاربری شما**
1543
 
1544
  🔹 **شناسه یکتا:** `{chat_id}`
 
1545
  🔹 **وضعیت اشتراک:** {status_text}{expire_info}
 
1546
 
1547
  📊 **سهمیه باقی‌مانده شما:**
1548
  - 💬 چت هوشمند: {chat_rem}
@@ -1557,7 +1515,58 @@ else:
1557
  await send_with_keyboard(client, chat_id, account_profile, True)
1558
  return
1559
 
1560
- # --- دکمه خرید اشتراک ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1561
  if user_text_str in["/buy", "خرید اشتراک 💎"]:
1562
  buy_text = f"""💎 **خرید اشتراک ویژه آلفا پرو (یک ماهه)**
1563
 
@@ -1589,7 +1598,6 @@ else:
1589
  await send_with_keyboard(client, chat_id, buy_text, True)
1590
  return
1591
 
1592
- # --- دکمه انتقال اکانت ---
1593
  if user_text_str in["/transfer", "انتقال اکانت از برنامه به ربات"]:
1594
  transfer_text = f"""🔄 **انتقال اکانت از برنامه به ربات**
1595
 
@@ -1605,55 +1613,128 @@ else:
1605
  return
1606
 
1607
  if user_text_str in["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
1608
- user_states[chat_id]["mode"] = "chat"
1609
- user_states[chat_id]["history"] =[]
1610
  await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n\nهر سوالی دارید بفرستید تا جواب بدم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1611
  return
1612
 
1613
  if user_text_str in["/image", "🎨 عکس", "ساخت تصاویر🎨"]:
1614
- user_states[chat_id]["mode"] = "image_waiting_for_text"
1615
  await send_with_keyboard(client, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\nمتن خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1616
  return
1617
 
1618
  if user_text_str in["/edit_image", "ویرایش تصاویر 🪄"]:
1619
- user_states[chat_id]["mode"] = "image_edit_waiting_for_image"
1620
- user_states[chat_id]["file_bytes"] = None
1621
  await send_with_keyboard(client, chat_id, "🪄 به بخش **ویرایش عکس (Flux.2)** خوش آمدید.\n\nلطفاً ابتدا عکسی که می‌خواهید ویرایش کنید را بفرستید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1622
  return
1623
 
1624
  if user_text_str in["/tts", "🎙️ صدا", "تبدیل متن به صدا🗣️"]:
1625
- user_states[chat_id]["mode"] = "tts_waiting_for_text"
1626
  await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1627
  return
1628
 
1629
  if user_text_str in["/podcast", "📻 پادکست", "ساخت پادکست 🎙️"]:
1630
- user_states[chat_id]["mode"] = "podcast_waiting_for_topic"
1631
  await send_with_keyboard(client, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز . همچنین این قسمت متصل به مدل زبانی است و درخواست هارو قبل از ساخت درک میکنه. میتوانید مقاله کامل یک سایت بفرستید با تبلیغات یا هرچی، هوش مصنوعی متن مقاله رو استخراج و پادکست براتون میسازه . در توضیحات امکان مشخص کردن تعداد گوینده به همراه اسم شون نیز از سمت شما امکان پذیر است.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1632
  return
1633
 
1634
  if user_text_str in["/file", "تحلیل فایل 📁"]:
1635
- user_states[chat_id]["mode"] = "file_waiting_for_file"
1636
- user_states[chat_id]["file_bytes"] = None
1637
  await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً فایل خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1638
  return
1639
 
1640
  if user_text_str in["/stt", "فایل صوتی به متن 📝"]:
1641
- user_states[chat_id]["mode"] = "stt_waiting_for_audio"
1642
  await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1643
  return
1644
 
1645
  if user_text_str in["/create_file", "ساخت فایل 📄"]:
1646
- user_states[chat_id]["mode"] = "create_file_waiting_for_topic"
1647
  await send_with_keyboard(client, chat_id, "📄 شما وارد بخش **ساخت فایل** شدید.\n\nلطفاً موضوع مقاله‌ای که می‌خواهید را کامل بفرستید.\nمثال: نحوه مدیریت زمان\n\nهوش مصنوعی یک مقاله کامل و طولانی نوشته و در نهایت فایل PDF و Word آن را به شما تحویل می‌دهد.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1648
  return
1649
 
1650
- current_mode = user_states[chat_id].get("mode")
1651
 
1652
  if current_mode is None:
1653
  if is_file: pass
1654
  elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
1655
  return
1656
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1657
  elif current_mode == "chat":
1658
  if is_file:
1659
  await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
@@ -1673,17 +1754,17 @@ else:
1673
  await send_with_keyboard(client, chat_id, "📥 در حال دانلود عکس...", False)
1674
  try:
1675
  file_bytes = await helper_download_file(client, msg_obj)
1676
- user_states[chat_id]["file_bytes"] = file_bytes
1677
- user_states[chat_id]["mode"] = "image_edit_waiting_for_prompt"
1678
  await send_with_keyboard(client, chat_id, "✅ عکس با موفقیت دریافت شد.\n\nحالا دستور خود را به صورت متنی تایپ کنید.\nمثال: یک کلاه قرمز روی سر این گربه بگذار.", False)
1679
  except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت عکس!\n{str(dl_err)}", False)
1680
  return
1681
 
1682
  elif current_mode == "image_edit_waiting_for_prompt":
1683
  if user_text_str:
1684
- saved_bytes = user_states[chat_id].get("file_bytes")
1685
- user_states[chat_id]["mode"] = None
1686
- user_states[chat_id]["file_bytes"] = None
1687
  asyncio.create_task(process_image_edit(client, chat_id, saved_bytes, user_text_str))
1688
  else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1689
  return
@@ -1691,8 +1772,8 @@ else:
1691
  elif current_mode == "tts_waiting_for_text":
1692
  if user_text_str:
1693
  if len(user_text_str) > 2500: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
1694
- user_states[chat_id]["text"] = user_text_str
1695
- user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
1696
 
1697
  speakers_menu = """✅ متن شما ذخیره شد.
1698
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
@@ -1714,8 +1795,8 @@ else:
1714
 
1715
  if normalized_text.isdigit() and normalized_text in SPEAKERS:
1716
  spk_name, spk_id = SPEAKERS[normalized_text]
1717
- txt = user_states[chat_id]["text"]
1718
- user_states[chat_id]["mode"] = "tts_waiting_for_text"
1719
  asyncio.create_task(process_tts(client, chat_id, txt, spk_id, spk_name))
1720
  else:
1721
  await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
@@ -1740,18 +1821,18 @@ else:
1740
  await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False)
1741
  try:
1742
  file_bytes = await helper_download_file(client, msg_obj)
1743
- user_states[chat_id]["file_bytes"] = file_bytes
1744
- user_states[chat_id]["file_name"] = file_name
1745
- user_states[chat_id]["mode"] = "file_waiting_for_prompt"
1746
  await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بگویید **چگونه تحلیل شود؟**", False)
1747
  except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
1748
  return
1749
 
1750
  elif current_mode == "file_waiting_for_prompt":
1751
  if user_text_str:
1752
- saved_bytes = user_states[chat_id].get("file_bytes")
1753
- saved_name = user_states[chat_id].get("file_name", "file.jpeg")
1754
- user_states[chat_id]["mode"] = "file_waiting_for_file"
1755
  asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str))
1756
  else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1757
  return
@@ -1768,5 +1849,5 @@ else:
1768
  if __name__ == "__main__":
1769
  threading.Thread(target=run_flask, daemon=True).start()
1770
  if bot_token:
1771
- print("ربات آلفا پرو با سیستم اشتراک نامحدود + سپر امنیتی Burst Controller روشن شد...")
1772
  bot.run()
 
79
  print("در حال تلاش برای خواندن دیتابیس کاربران از دیتاست هاگینگ فیس...")
80
  if HF_TOKEN_DB:
81
  try:
 
82
  file_path = hf_hub_download(
83
  repo_id=DATASET_REPO,
84
  filename=DB_FILE,
 
89
  print("✅ دیتابیس با موفقیت از دیتاست هاگینگ فیس لود شد.")
90
  return json.load(f)
91
  except Exception as e:
92
+ print("⚠️ فایل دیتابیس در هاگینگ فیس یافت نشد یا خطایی رخ داد (ساخت دیتابیس جدید).")
93
 
 
94
  if os.path.exists(DB_FILE):
95
  try:
96
  with open(DB_FILE, "r", encoding="utf-8") as f:
 
100
  return {}
101
 
102
  def _upload_db_background():
 
103
  if HF_TOKEN_DB:
104
  api = HfApi(token=HF_TOKEN_DB)
105
  try:
 
115
  def save_db(db_data):
116
  with db_lock:
117
  try:
 
118
  with open(DB_FILE, "w", encoding="utf-8") as f:
119
  json.dump(db_data, f, ensure_ascii=False, indent=4)
 
 
120
  threading.Thread(target=_upload_db_background, daemon=True).start()
121
  except Exception as e:
122
  print("خطا در ذخیره دیتابیس:", e)
123
 
124
  user_credits_db = load_db()
125
 
126
+ # --- سیستم تولید و یافتن کد هدیه 8 رقمی یکتا ---
127
+ def get_or_create_referral_code(chat_id):
128
+ user_data = user_credits_db[chat_id]
129
+ if not user_data.get("referral_code"):
130
+ while True:
131
+ # فقط از اعداد برای تولید کد 8 رقمی استفاده می‌کنیم
132
+ new_code = ''.join(random.choices(string.digits, k=8))
133
+ exists = any(u.get("referral_code") == new_code for u in user_credits_db.values())
134
+ if not exists:
135
+ user_data["referral_code"] = new_code
136
+ save_db(user_credits_db)
137
+ break
138
+ return user_data["referral_code"]
139
+
140
+ def find_user_by_referral_code(code):
141
+ code = code.strip()
142
+ for uid, data in user_credits_db.items():
143
+ if data.get("referral_code", "") == code:
144
+ return uid
145
+ return None
146
+
147
  def get_user_credits(chat_id):
 
148
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
149
  today_str = datetime.date.today().isoformat()
150
 
151
  if str_chat_id not in user_credits_db:
 
152
  user_credits_db[str_chat_id] = {
153
  "is_premium": False,
154
  "expire_date": None,
 
160
  "tts": 5,
161
  "file": 1,
162
  "stt": 5,
163
+ "has_joined": False,
164
+ "invited_count": 0,
165
+ "used_referral": False,
166
+ "referral_code": ""
167
  }
168
  save_db(user_credits_db)
169
 
170
  user_data = user_credits_db[str_chat_id]
171
  is_premium = user_data.get("is_premium", False)
172
 
 
173
  if is_premium and user_data.get("expire_date"):
174
  try:
175
  expire_date = datetime.datetime.fromisoformat(user_data["expire_date"])
176
  if datetime.datetime.now() > expire_date:
 
177
  user_data["is_premium"] = False
178
  user_data["expire_date"] = None
179
  is_premium = False
180
  except Exception:
181
  pass
182
 
 
183
  if not is_premium:
184
  if user_data.get("last_reset") != today_str:
185
  user_data["last_reset"] = today_str
 
186
  user_data["chat"] = 10
187
  user_data["image"] = 5
188
  user_data["edit_image"] = 1
 
209
 
210
  @app.route('/')
211
  def home():
212
+ return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دعوت دوستان + سیستم ضد باگ) روشن است! 🚀"
213
 
214
  def run_flask():
215
  app.run(host="0.0.0.0", port=7860)
 
252
  {"id": "buy_btn", "type": "Simple", "button_text": "خرید اشتراک 💎"}
253
  ]
254
  },
255
+ {
256
+ "buttons":[
257
+ {"id": "invite_btn", "type": "Simple", "button_text": "دعوت دوستان 🎁"},
258
+ {"id": "referral_btn", "type": "Simple", "button_text": "ثبت کد هدیه 🎫"}
259
+ ]
260
+ },
261
  {
262
  "buttons":[
263
  {"id": "transfer_btn", "type": "Simple", "button_text": "انتقال اکانت از برنامه به ربات"}
 
272
  "resize_keyboard": True
273
  }
274
 
 
275
  CHANNEL_USERNAME = "aialpha"
276
  CHANNEL_GUID = None
277
 
 
288
 
289
  async def check_channel_membership(client, user_id):
290
  global CHANNEL_GUID
 
291
  if str(user_id) == str(BOT_GUID): return True
292
 
293
  try:
 
309
  CHANNEL_GUID = getattr(res.exist.chat, 'object_guid', None)
310
 
311
  if not CHANNEL_GUID:
312
+ return True
313
 
314
  payload = {
315
  "channel_guid": CHANNEL_GUID,
 
328
 
329
  return False
330
  except Exception:
331
+ return False
332
 
333
 
 
334
  async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
335
  try:
336
  if not use_keyboard:
 
350
  return None
351
 
352
 
 
353
  async def helper_download_file(client, msg_obj):
354
  errors =[]
355
  file_id = None
 
362
  elif isinstance(val, dict) and 'file_id' in val: file_id = val['file_id']
363
  if file_id: break
364
 
 
365
  temp_name = f"temp_dl_{uuid.uuid4().hex}.tmp"
366
 
367
  if hasattr(client, "download_file"):
 
402
  raise Exception("دانلود ناموفق. لاگ:\n" + "\n".join(errors))
403
 
404
 
 
405
  GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "")
406
  GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "")
407
 
 
411
  if GEMINI_KEYS_STR2:
412
  _raw_keys.extend(GEMINI_KEYS_STR2.split(","))
413
 
 
414
  GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()]))
415
  print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.")
416
 
 
417
  current_gemini_key_index = 0
418
  gemini_key_lock = threading.Lock()
419
 
420
  def get_next_gemini_keys(count=100):
 
 
 
 
 
 
421
  global current_gemini_key_index
422
  with gemini_key_lock:
423
  total_keys = len(GEMINI_KEYS)
 
439
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
440
 
441
 
 
442
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
443
  abs_path = os.path.abspath(file_name)
444
  error_logs =[]
445
 
446
  api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in["voice", "Voice", "audio"] else "File"
447
 
 
448
  if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
449
  api_file_type = "Music"
450
 
 
451
  for attempt in range(3):
452
  try:
453
  url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
454
  url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
455
 
456
  async with aiohttp.ClientSession() as session:
 
457
  async with session.post(url_request, json={"type": api_file_type}, timeout=20) as resp:
458
  if resp.status != 200:
459
  error_logs.append(f"Request HTTP {resp.status}")
 
465
  if req_data.get("status") == "OK":
466
  upload_url = req_data.get("data", {}).get("upload_url")
467
 
 
468
  if upload_url:
469
  with open(abs_path, "rb") as f:
470
  form = aiohttp.FormData()
471
  form.add_field('file', f, filename=os.path.basename(abs_path))
472
 
 
473
  async with session.post(upload_url, data=form, timeout=60) as up_resp:
474
  if up_resp.status != 200:
475
  error_logs.append(f"Upload HTTP {up_resp.status}")
 
476
  if up_resp.status == 502 and api_file_type == "Voice":
477
  api_file_type = "Music"
478
  await asyncio.sleep(1.5)
 
485
  await asyncio.sleep(1.5)
486
  continue
487
 
 
488
  final_file_id = None
489
  if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
490
  if "data" in up_data and isinstance(up_data["data"], dict):
 
493
  final_file_id = up_data.get("file_id")
494
 
495
  if final_file_id:
 
496
  send_payload = {
497
  "chat_id": str(chat_id),
498
  "file_id": str(final_file_id),
 
512
  else:
513
  error_logs.append(f"SendFile API Error: {s_data}")
514
  else:
 
515
  if up_data.get("status") == "INVALID_INPUT" and api_file_type == "Voice":
516
  api_file_type = "Music"
517
  error_logs.append(f"Upload API Error: {up_data}")
 
523
  error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
524
  await asyncio.sleep(1.5)
525
 
 
526
  try:
527
  if hasattr(client, "send_file"):
528
  await client.send_file(chat_id, abs_path)
 
560
  user_last_request_time = {}
561
 
562
 
 
563
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
564
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
565
  creds = get_user_credits(str_chat_id)
 
596
  history = history[-40:]
597
  if history[0]["role"] == "model": history = history[1:]
598
 
 
599
  keys_to_try = get_next_gemini_keys(100)
600
  final_answer = None
601
 
 
613
  except (KeyError, IndexError): continue
614
  except Exception: continue
615
 
 
616
  if not final_answer and HF_TOKENS:
617
  hf_messages =[]
618
  for msg in history:
 
663
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", False)
664
  return
665
 
 
666
  if not creds.get("is_premium"):
667
  user_credits_db[str_chat_id]["chat"] -= 1
668
  save_db(user_credits_db)
 
693
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
694
 
695
 
 
696
  async def process_image(client, chat_id, prompt):
697
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
698
  creds = get_user_credits(str_chat_id)
 
706
  gemini_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}"
707
 
708
  if GEMINI_KEYS:
 
709
  keys_to_try_gemini = get_next_gemini_keys(100)
710
  async with aiohttp.ClientSession() as session:
711
  for key in keys_to_try_gemini:
 
719
  break
720
  except Exception: continue
721
 
 
722
  if enhanced_prompt == prompt and HF_TOKENS:
723
  keys_to_try_hf = HF_TOKENS.copy()
724
  random.shuffle(keys_to_try_hf)
 
744
  if proc_msg:
745
  msg_id = getattr(proc_msg, 'message_id', None)
746
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
747
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
748
  except Exception: pass
749
 
750
  short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
 
773
 
774
  if not generated_image: return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
775
 
 
776
  user_credits_db[str_chat_id]["image"] -= 1
777
  save_db(user_credits_db)
778
 
 
787
  if os.path.exists(file_name): os.remove(file_name)
788
  except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
789
 
790
+
791
  async def translate_text_aloha(prompt_text):
792
  session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
793
  join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join"
 
799
 
800
  try:
801
  async with aiohttp.ClientSession() as session:
 
802
  async with session.post(join_url, json=payload, timeout=20) as resp:
803
  if resp.status != 200:
804
  return prompt_text
805
 
 
806
  data_url = f"https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/data?session_hash={session_hash}"
807
  async with session.get(data_url, timeout=60) as resp:
808
  async for line_bytes in resp.content:
 
821
 
822
  return prompt_text
823
 
824
+
825
  async def process_image_edit(client, chat_id, image_bytes, prompt):
826
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
827
  creds = get_user_credits(str_chat_id)
 
833
 
834
  proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال ترجمه دستور شما توسط اسپیس و اعمال جادوی FLUX.2...\n(این فرآیند ممکن است کمی طول بکشد)", False)
835
 
 
836
  translated_prompt = await translate_text_aloha(prompt)
837
  if not translated_prompt or translated_prompt.strip() == "":
838
  translated_prompt = prompt
 
865
  if not generated_image:
866
  return await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
867
 
 
868
  user_credits_db[str_chat_id]["edit_image"] -= 1
869
  save_db(user_credits_db)
870
 
 
882
  await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
883
 
884
 
 
885
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
886
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
887
  creds = get_user_credits(str_chat_id)
 
918
  except Exception: pass
919
 
920
  if audio_bytes:
 
921
  if not creds.get("is_premium"):
922
  user_credits_db[str_chat_id]["tts"] -= 1
923
  save_db(user_credits_db)
924
 
 
925
  file_name_mp3 = f"audio_{uuid.uuid4().hex}.mp3"
926
 
927
  with open(file_name_mp3, "wb") as f: f.write(audio_bytes)
928
 
929
  await asyncio.sleep(1)
 
 
930
  upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
931
 
932
  if upload_result_file is not True:
 
937
  except Exception: traceback.print_exc()
938
 
939
 
 
940
  async def process_podcast(client, chat_id, prompt):
941
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
942
  creds = get_user_credits(str_chat_id)
 
1006
  combined_audio += audio_segment
1007
  except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا (آیا pydub و ffmpeg نصب است؟):\n{str(e)}", True)
1008
 
 
1009
  if not creds.get("is_premium"):
1010
  user_credits_db[str_chat_id]["podcast"] -= 1
1011
  save_db(user_credits_db)
1012
 
 
1013
  file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
1014
  combined_audio.export(file_name_mp3, format="mp3")
1015
 
 
1021
  except: pass
1022
 
1023
  caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
 
 
1024
  upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", caption_file)
1025
 
1026
  if upload_result_file is not True:
 
1029
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1030
 
1031
 
 
1032
  async def process_stt(client, chat_id, audio_bytes, file_name):
1033
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1034
  creds = get_user_credits(str_chat_id)
 
1042
  mime_type, _ = mimetypes.guess_type(file_name)
1043
  if not mime_type: mime_type = "audio/ogg"
1044
 
 
1045
  keys_to_try = get_next_gemini_keys(100)
1046
  transcribed_text = None
1047
  prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
 
1049
  async with aiohttp.ClientSession() as session:
1050
  for key in keys_to_try:
1051
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1052
+ payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.2}}
1053
  try:
1054
  async with session.post(url, json=payload, timeout=60) as response:
1055
  if response.status == 200:
 
1066
  except Exception: pass
1067
 
1068
  if transcribed_text:
 
1069
  if not creds.get("is_premium"):
1070
  user_credits_db[str_chat_id]["stt"] -= 1
1071
  save_db(user_credits_db)
 
1074
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1075
 
1076
 
 
1077
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1078
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1079
  creds = get_user_credits(str_chat_id)
 
1087
  mime_type, _ = mimetypes.guess_type(file_name)
1088
  if not mime_type: mime_type = "image/jpeg"
1089
 
 
1090
  keys_to_try = get_next_gemini_keys(100)
1091
  final_answer = None
1092
 
1093
  async with aiohttp.ClientSession() as session:
1094
  for key in keys_to_try:
1095
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1096
+ payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.6}}
1097
  try:
1098
  async with session.post(url, json=payload, timeout=45) as response:
1099
  if response.status == 200:
 
1110
  except Exception: pass
1111
 
1112
  if final_answer:
 
1113
  if not creds.get("is_premium"):
1114
  user_credits_db[str_chat_id]["file"] -= 1
1115
  save_db(user_credits_db)
 
1118
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1119
 
1120
 
 
1121
  async def process_create_file(client, chat_id, topic):
1122
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1123
  creds = get_user_credits(str_chat_id)
1124
 
 
1125
  if creds["chat"] <= 0:
1126
  return await send_with_keyboard(client, chat_id, "❌ اعتبار چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1127
 
 
1145
  break
1146
  except Exception: continue
1147
 
 
1148
  if not article_text and HF_TOKENS:
1149
  keys_to_try_hf = HF_TOKENS.copy()
1150
  random.shuffle(keys_to_try_hf)
 
1182
  converter_url = "https://opera8-texttopdf.hf.space/"
1183
 
1184
  async with aiohttp.ClientSession() as session:
 
1185
  try:
1186
  form_data_pdf = aiohttp.FormData()
1187
  form_data_pdf.add_field('content', article_text)
 
1191
  pdf_bytes = await resp.read()
1192
  except Exception as e: print("PDF creation error:", e)
1193
 
 
1194
  try:
1195
  form_data_docx = aiohttp.FormData()
1196
  form_data_docx.add_field('content', article_text)
 
1210
  if not pdf_bytes and not docx_bytes:
1211
  return await send_with_keyboard(client, chat_id, "❌ متاسفانه در تبدیل متن به فایل خطایی رخ داد.", True)
1212
 
 
1213
  if not creds.get("is_premium"):
1214
  user_credits_db[str_chat_id]["chat"] -= 1
1215
  save_db(user_credits_db)
 
1241
  await send_with_keyboard(client, chat_id, "❌ فایل‌ها ساخته شدند اما روبیکا در ارسال آن‌ها دچار مشکل شد.", True)
1242
 
1243
 
 
1244
  if not bot_token:
1245
  print("خطا: توکن ربات روبیکا وارد نشده است!")
1246
  else:
 
1250
  async def main_handler(client, update):
1251
  global BOT_GUID
1252
 
 
 
1253
  if is_backlog_burst():
1254
  return
1255
 
1256
  try:
 
1257
  if not BOT_GUID:
1258
  try:
1259
  me_info = await client.get_me()
 
1264
 
1265
  msg_obj = getattr(update, "message", None) or getattr(update, "new_message", None)
1266
 
 
1267
  author_id = getattr(update, 'author_guid', None)
1268
  if not author_id and msg_obj:
1269
  author_id = msg_obj.get('author_object_guid') if isinstance(msg_obj, dict) else getattr(msg_obj, 'author_object_guid', None)
1270
 
 
1271
  if BOT_GUID and author_id == BOT_GUID:
1272
  return
1273
 
 
1274
  chat_id = getattr(update, 'object_guid', None) or getattr(update, 'author_guid', None) or getattr(update, "chat_id", None)
1275
  if not chat_id: return
1276
 
 
1277
  msg_id = getattr(update, "message_id", None)
1278
  if not msg_id and msg_obj:
1279
  msg_id = msg_obj.get("message_id") if isinstance(msg_obj, dict) else getattr(msg_obj, "message_id", None)
1280
 
 
1281
  unique_msg_key = f"{chat_id}_{msg_id}" if msg_id else None
1282
  if unique_msg_key:
1283
  if unique_msg_key in processed_message_ids: return
 
1286
 
1287
  current_time = time.time()
1288
 
 
1289
  last_req_time = user_last_request_time.get(chat_id, 0)
1290
  if current_time - last_req_time < 1.0:
1291
  return
1292
  user_last_request_time[chat_id] = current_time
1293
 
 
1294
  user_text = getattr(update, "text", "") or getattr(msg_obj, "text", "")
1295
  user_text_str = str(user_text).strip() if user_text else ""
1296
  user_text_lower = user_text_str.lower()
1297
 
1298
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1299
+
1300
+ if str_chat_id not in user_states:
1301
+ user_states[str_chat_id] = {"mode": None, "text": "", "history":[], "file_bytes": None, "file_name": None}
1302
+
1303
+ creds = get_user_credits(str_chat_id)
1304
 
 
1305
  if user_text_lower.startswith(f"{ADMIN_CODE} pro=") or user_text_lower.startswith(f"{ADMIN_CODE}pro="):
1306
  parts = user_text_str.split("=", 1)
1307
  if len(parts) >= 2:
 
1319
  "tts": 5,
1320
  "file": 1,
1321
  "stt": 5,
1322
+ "has_joined": True,
1323
+ "invited_count": 0,
1324
+ "used_referral": False,
1325
+ "referral_code": ""
1326
  }
1327
 
1328
  user_credits_db[target_id]["is_premium"] = True
 
1391
  stt_rem = "نامحدود ∞" if is_prem else t_creds.get('stt', 0)
1392
  image_rem = t_creds.get('image', 0)
1393
  edit_image_rem = t_creds.get('edit_image', 0)
1394
+ invs = t_creds.get('invited_count', 0)
1395
 
1396
  info_msg = f"""🔍 **اطلاعات کاربر `{target_id}`:**
1397
 
1398
  🔹 **وضعیت:** {status_text}
1399
+ 🎁 **تعداد افراد دعوت شده:** {invs} نفر
1400
 
1401
  📊 **سهمیه:**
1402
  - چت: {chat_rem}
 
1411
  await send_with_keyboard(client, chat_id, f"❌ کاربری با شناسه `{target_id}` در دیتابیس یافت نشد.", False)
1412
  return
1413
 
 
1414
  is_file = False
1415
  file_name = f"unknown_file_{uuid.uuid4().hex[:6]}.jpg"
1416
 
 
1431
  file_name = file_attr.get('file_name', file_name) if isinstance(file_attr, dict) else file_name
1432
  break
1433
 
 
 
 
 
1434
  if user_text_str == "✅ عضو شدم":
1435
  if not creds.get("has_joined", False):
 
1436
  user_credits_db[str_chat_id]["has_joined"] = True
1437
  save_db(user_credits_db)
1438
  await send_with_keyboard(client, chat_id, "🎉 **عضویت شما با موفقیت تایید شد! خیلی خوش آمدید.**\n\nحالا می‌توانید از تمامی امکانات ربات استفاده کنید.\nلطفاً یکی از گزینه‌های منو را انتخاب کنید:", True)
 
1450
  await client.send_message(chat_id, join_msg)
1451
  return
1452
 
1453
+ if user_text_lower.startswith("/start"):
1454
+ user_states[str_chat_id]["mode"] = None
1455
+ user_states[str_chat_id]["file_bytes"] = None
1456
+ await send_with_keyboard(client, chat_id, "سلام! به ربات هوش مصنوعی آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
1457
+ return
1458
+
1459
+ if user_text_str in["سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
1460
+ user_states[str_chat_id]["mode"] = None
1461
+ user_states[str_chat_id]["file_bytes"] = None
1462
  await send_with_keyboard(client, chat_id, "سلام! به ربات هوش مصنوعی آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
1463
  return
1464
 
 
1465
  if user_text_str in["/account", "حساب کاربری 👤"]:
 
1466
  is_prem = creds.get("is_premium", False)
1467
 
1468
  if is_prem:
 
1492
  stt_rem = "نامحدود ∞" if is_prem else creds['stt']
1493
  image_rem = creds['image']
1494
  edit_image_rem = creds['edit_image']
1495
+ invited_count = creds.get('invited_count', 0)
1496
+ my_code = get_or_create_referral_code(str_chat_id)
1497
 
1498
  account_profile = f"""👤 **اطلاعات حساب کاربری شما**
1499
 
1500
  🔹 **شناسه یکتا:** `{chat_id}`
1501
+ 🎫 **کد هدیه شما:** `{my_code}`
1502
  🔹 **وضعیت اشتراک:** {status_text}{expire_info}
1503
+ 🎁 **تعداد افراد دعوت شده:** {invited_count} نفر
1504
 
1505
  📊 **سهمیه باقی‌مانده شما:**
1506
  - 💬 چت هوشمند: {chat_rem}
 
1515
  await send_with_keyboard(client, chat_id, account_profile, True)
1516
  return
1517
 
1518
+ # ===============================================
1519
+ # 🎁 سیستم جدید دعوت دوستان (دو سر سود) 🎁
1520
+ # ===============================================
1521
+ if user_text_str in["/invite", "دعوت دوستان 🎁"]:
1522
+ invites = creds.get("invited_count", 0)
1523
+ remains = 10 - (invites % 10)
1524
+ my_code = get_or_create_referral_code(str_chat_id)
1525
+
1526
+ invite_text = f"""🎁 **سیستم دعوت دوستان (دو سر سود)**
1527
+
1528
+ با دعوت دوستان خود به ربات آلفا، هم شما و هم دوستتان هدیه می‌گیرید!
1529
+ به دوست خود بگویید پس از ورو�� به ربات، دکمه **«ثبت کد هدیه 🎫»** را بزند و کد زیر را وارد کند.
1530
+ ✨ **سود دوست شما:** در همان لحظه 10 تبدیل رایگان متن به صدا دریافت می‌کند.
1531
+ ✨ **سود شما:** به آمار دعوت‌هایتان اضافه می‌شود و به ازای هر **10 نفر**، **3 روز اشتراک پرو نامحدود** می‌گیرید.
1532
+
1533
+ 📊 **آمار شما:**
1534
+ - تعداد دعوت‌های موفق: {invites} نفر
1535
+ - دعوت‌های باقی‌مانده تا جایزه بعدی: {remains} نفر
1536
+
1537
+ کد هدیه اختصاصی شما:
1538
+ `{my_code}`
1539
+
1540
+ (متن زیر را کپی کرده و برای دوستانتان بفرستید 👇)"""
1541
+ await send_with_keyboard(client, chat_id, invite_text, True)
1542
+
1543
+ forward_text = f"""🤖 **ربات هوش مصنوعی آلفا پرو**
1544
+
1545
+ ✨ با این ربات می‌تونی کارهای زیر رو به راحتی انجام بدی:
1546
+ 💬 چت با پیشرفته‌ترین هوش مصنوعی
1547
+ 🎨 ساخت و ویرایش حرفه‌ای عکس
1548
+ 🎙 ساخت پادکست اختصاصی
1549
+ 🗣 تبدیل متن به صدا (30 گوینده مختلف)
1550
+ 📝 تبدیل صدا و ویدیو به متن
1551
+ 📁 تحلیل فایل‌ها و ساخت مقاله
1552
+
1553
+ 👇 اول وارد ربات زیر شو:
1554
+ @aialphabot
1555
+
1556
+ سپس دکمه **«ثبت کد هدیه 🎫»** را بزن و کد 8 رقمی زیر رو وارد کن تا همون اول **10 تا تبدیل صدا هدیه بگیری**:
1557
+ `{my_code}`"""
1558
+ await send_with_keyboard(client, chat_id, forward_text, False)
1559
+ return
1560
+
1561
+ if user_text_str in["/referral", "ثبت کد هدیه 🎫"]:
1562
+ if creds.get("used_referral", False):
1563
+ await send_with_keyboard(client, chat_id, "❌ شما قبلاً کد هدیه یک نفر را ثبت کرده‌اید و فقط یک‌بار مجاز به استفاده از این امکان هستید.", True)
1564
+ return
1565
+ user_states[str_chat_id]["mode"] = "waiting_for_referral_code"
1566
+ msg = "🎫 **ثبت کد هدیه**\n\nکد هدیه 8 رقمی (اعداد) که از دوست خود دریافت کرده‌اید را اینجا وارد کنید تا در همان لحظه **10 سهمیه تبدیل رایگان متن به صدا** هدیه بگیرید!\n\n(برای انصراف دکمه «برگشت♻️» را بزنید)"
1567
+ await send_with_keyboard(client, chat_id, msg, True)
1568
+ return
1569
+
1570
  if user_text_str in["/buy", "خرید اشتراک 💎"]:
1571
  buy_text = f"""💎 **خرید اشتراک ویژه آلفا پرو (یک ماهه)**
1572
 
 
1598
  await send_with_keyboard(client, chat_id, buy_text, True)
1599
  return
1600
 
 
1601
  if user_text_str in["/transfer", "انتقال اکانت از برنامه به ربات"]:
1602
  transfer_text = f"""🔄 **انتقال اکانت از برنامه به ربات**
1603
 
 
1613
  return
1614
 
1615
  if user_text_str in["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
1616
+ user_states[str_chat_id]["mode"] = "chat"
1617
+ user_states[str_chat_id]["history"] =[]
1618
  await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n\nهر سوالی دارید بفرستید تا جواب بدم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1619
  return
1620
 
1621
  if user_text_str in["/image", "🎨 عکس", "ساخت تصاویر🎨"]:
1622
+ user_states[str_chat_id]["mode"] = "image_waiting_for_text"
1623
  await send_with_keyboard(client, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\nمتن خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1624
  return
1625
 
1626
  if user_text_str in["/edit_image", "ویرایش تصاویر 🪄"]:
1627
+ user_states[str_chat_id]["mode"] = "image_edit_waiting_for_image"
1628
+ user_states[str_chat_id]["file_bytes"] = None
1629
  await send_with_keyboard(client, chat_id, "🪄 به بخش **ویرایش عکس (Flux.2)** خوش آمدید.\n\nلطفاً ابتدا عکسی که می‌خواهید ویرایش کنید را بفرستید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1630
  return
1631
 
1632
  if user_text_str in["/tts", "🎙️ صدا", "تبدیل متن به صدا🗣️"]:
1633
+ user_states[str_chat_id]["mode"] = "tts_waiting_for_text"
1634
  await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1635
  return
1636
 
1637
  if user_text_str in["/podcast", "📻 پادکست", "ساخت پادکست 🎙️"]:
1638
+ user_states[str_chat_id]["mode"] = "podcast_waiting_for_topic"
1639
  await send_with_keyboard(client, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز . همچنین این قسمت متصل به مدل زبانی است و درخواست هارو قبل از ساخت درک میکنه. میتوانید مقاله کامل یک سایت بفرستید با تبلیغات یا هرچی، هوش مصنوعی متن مقاله رو استخراج و پادکست براتون میسازه . در توضیحات امکان مشخص کردن تعداد گوینده به همراه اسم شون نیز از سمت شما امکان پذیر است.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1640
  return
1641
 
1642
  if user_text_str in["/file", "تحلیل فایل 📁"]:
1643
+ user_states[str_chat_id]["mode"] = "file_waiting_for_file"
1644
+ user_states[str_chat_id]["file_bytes"] = None
1645
  await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً فایل خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1646
  return
1647
 
1648
  if user_text_str in["/stt", "فایل صوتی به متن 📝"]:
1649
+ user_states[str_chat_id]["mode"] = "stt_waiting_for_audio"
1650
  await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1651
  return
1652
 
1653
  if user_text_str in["/create_file", "ساخت فایل 📄"]:
1654
+ user_states[str_chat_id]["mode"] = "create_file_waiting_for_topic"
1655
  await send_with_keyboard(client, chat_id, "📄 شما وارد بخش **ساخت فایل** شدید.\n\nلطفاً موضوع مقاله‌ای که می‌خواهید را کامل بفرستید.\nمثال: نحوه مدیریت زمان\n\nهوش مصنوعی یک مقاله کامل و طولانی نوشته و در نهایت فایل PDF و Word آن را به شما تحویل می‌دهد.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1656
  return
1657
 
1658
+ current_mode = user_states[str_chat_id].get("mode")
1659
 
1660
  if current_mode is None:
1661
  if is_file: pass
1662
  elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
1663
  return
1664
 
1665
+ # ===============================================
1666
+ # بخش دریافت کد هدیه 8 رقمی از کاربر
1667
+ # ===============================================
1668
+ elif current_mode == "waiting_for_referral_code":
1669
+ if user_text_str:
1670
+ # تبدیل به اعداد انگلیسی در صورت استفاده از کیبورد فارسی
1671
+ normalized_code = to_english_digits(user_text_str).strip()
1672
+
1673
+ if not normalized_code.isdigit() or len(normalized_code) != 8:
1674
+ await send_with_keyboard(client, chat_id, "❌ کد وارد شده نامعتبر است. لطفاً یک کد 8 رقمی صحیح بفرستید.", False)
1675
+ return
1676
+
1677
+ inviter_id = find_user_by_referral_code(normalized_code)
1678
+
1679
+ if not inviter_id:
1680
+ await send_with_keyboard(client, chat_id, "❌ کد هدیه یافت نشد. لطفاً کد را با دقت بررسی کنید.", False)
1681
+ return
1682
+
1683
+ if str(inviter_id) == str(str_chat_id):
1684
+ await send_with_keyboard(client, chat_id, "❌ شما نمی‌توانید کد خودتان را ثبت کنید!", False)
1685
+ return
1686
+
1687
+ user_states[str_chat_id]["mode"] = None
1688
+
1689
+ # 1. پاداش کاربر دعوت شده (اضافه شدن 10 تبدیل صدا)
1690
+ user_credits_db[str_chat_id]["used_referral"] = True
1691
+ user_credits_db[str_chat_id]["tts"] = user_credits_db[str_chat_id].get("tts", 0) + 10
1692
+
1693
+ # 2. پاداش شخص دعوت کننده
1694
+ user_credits_db[inviter_id]["invited_count"] = user_credits_db[inviter_id].get("invited_count", 0) + 1
1695
+ current_invites = user_credits_db[inviter_id]["invited_count"]
1696
+
1697
+ if current_invites > 0 and current_invites % 10 == 0:
1698
+ inviter_data = user_credits_db[inviter_id]
1699
+ inviter_data["is_premium"] = True
1700
+ now = datetime.datetime.now()
1701
+ if inviter_data.get("expire_date"):
1702
+ try:
1703
+ current_exp = datetime.datetime.fromisoformat(inviter_data["expire_date"])
1704
+ if current_exp > now:
1705
+ new_exp = current_exp + datetime.timedelta(days=3)
1706
+ else:
1707
+ new_exp = now + datetime.timedelta(days=3)
1708
+ except:
1709
+ new_exp = now + datetime.timedelta(days=3)
1710
+ else:
1711
+ new_exp = now + datetime.timedelta(days=3)
1712
+
1713
+ inviter_data["expire_date"] = new_exp.isoformat()
1714
+ inviter_data["chat"] = 999999
1715
+ inviter_data["image"] = 20
1716
+ inviter_data["edit_image"] = 10
1717
+ inviter_data["podcast"] = 999999
1718
+ inviter_data["tts"] = 999999
1719
+ inviter_data["file"] = 999999
1720
+ inviter_data["stt"] = 999999
1721
+
1722
+ save_db(user_credits_db)
1723
+ try:
1724
+ msg_text = f"🎉 **تبریک ویژه!**\nیک دوست کد هدیه شما را ثبت کرد.\nتعداد کل دعوت‌های شما: {current_invites} نفر\n\n🎁 **هدیه شما:** ۳ روز اشتراک پرو نامحدود به حساب شما افزوده شد!"
1725
+ asyncio.create_task(send_with_keyboard(client, inviter_id, msg_text, True))
1726
+ except: pass
1727
+ else:
1728
+ save_db(user_credits_db)
1729
+ remains = 10 - (current_invites % 10)
1730
+ try:
1731
+ msg_text = f"🎉 **تبریک!**\nیک دوست کد هدیه شما را ثبت کرد.\nتعداد کل دعوت‌های شما: {current_invites} نفر\n\n⏳ با دعوت {remains} نفر دیگر، ۳ روز اشتراک رایگان دریافت می‌کنید!"
1732
+ asyncio.create_task(send_with_keyboard(client, inviter_id, msg_text, True))
1733
+ except: pass
1734
+
1735
+ await send_with_keyboard(client, chat_id, "✅ کد هدیه با موفقیت ثبت شد!\n🎁 **10 سهمیه تبدیل رایگان متن به صدا** به حساب شما اضافه گردید.", True)
1736
+ return
1737
+
1738
  elif current_mode == "chat":
1739
  if is_file:
1740
  await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
 
1754
  await send_with_keyboard(client, chat_id, "📥 در حال دانلود عکس...", False)
1755
  try:
1756
  file_bytes = await helper_download_file(client, msg_obj)
1757
+ user_states[str_chat_id]["file_bytes"] = file_bytes
1758
+ user_states[str_chat_id]["mode"] = "image_edit_waiting_for_prompt"
1759
  await send_with_keyboard(client, chat_id, "✅ عکس با موفقیت دریافت شد.\n\nحالا دستور خود را به صورت متنی تایپ کنید.\nمثال: یک کلاه قرمز روی سر این گربه بگذار.", False)
1760
  except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت عکس!\n{str(dl_err)}", False)
1761
  return
1762
 
1763
  elif current_mode == "image_edit_waiting_for_prompt":
1764
  if user_text_str:
1765
+ saved_bytes = user_states[str_chat_id].get("file_bytes")
1766
+ user_states[str_chat_id]["mode"] = None
1767
+ user_states[str_chat_id]["file_bytes"] = None
1768
  asyncio.create_task(process_image_edit(client, chat_id, saved_bytes, user_text_str))
1769
  else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1770
  return
 
1772
  elif current_mode == "tts_waiting_for_text":
1773
  if user_text_str:
1774
  if len(user_text_str) > 2500: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
1775
+ user_states[str_chat_id]["text"] = user_text_str
1776
+ user_states[str_chat_id]["mode"] = "tts_waiting_for_speaker"
1777
 
1778
  speakers_menu = """✅ متن شما ذخیره شد.
1779
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
 
1795
 
1796
  if normalized_text.isdigit() and normalized_text in SPEAKERS:
1797
  spk_name, spk_id = SPEAKERS[normalized_text]
1798
+ txt = user_states[str_chat_id]["text"]
1799
+ user_states[str_chat_id]["mode"] = "tts_waiting_for_text"
1800
  asyncio.create_task(process_tts(client, chat_id, txt, spk_id, spk_name))
1801
  else:
1802
  await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
 
1821
  await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False)
1822
  try:
1823
  file_bytes = await helper_download_file(client, msg_obj)
1824
+ user_states[str_chat_id]["file_bytes"] = file_bytes
1825
+ user_states[str_chat_id]["file_name"] = file_name
1826
+ user_states[str_chat_id]["mode"] = "file_waiting_for_prompt"
1827
  await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بگویید **چگونه تحلیل شود؟**", False)
1828
  except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
1829
  return
1830
 
1831
  elif current_mode == "file_waiting_for_prompt":
1832
  if user_text_str:
1833
+ saved_bytes = user_states[str_chat_id].get("file_bytes")
1834
+ saved_name = user_states[str_chat_id].get("file_name", "file.jpeg")
1835
+ user_states[str_chat_id]["mode"] = "file_waiting_for_file"
1836
  asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str))
1837
  else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1838
  return
 
1849
  if __name__ == "__main__":
1850
  threading.Thread(target=run_flask, daemon=True).start()
1851
  if bot_token:
1852
+ print("ربات آلفا پرو با سیستم اشتراک نامحدود + کد هدیه یکتا + سپر امنیتی روشن شد...")
1853
  bot.run()