Opera8 commited on
Commit
0dd8be0
·
verified ·
1 Parent(s): 3d71918

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +145 -33
main.py CHANGED
@@ -8,6 +8,8 @@ import asyncio
8
  import base64
9
  import mimetypes
10
  import io
 
 
11
  from flask import Flask
12
  from rubpy.bot import BotClient, filters
13
 
@@ -19,6 +21,52 @@ from pydub import AudioSegment
19
  # --- ثبت زمان روشن شدن ربات برای جلوگیری از پرتاب پیام‌های قدیمی ---
20
  BOT_STARTUP_TIME = time.time()
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  # --- تابع تبدیل اعداد فارسی/عربی به انگلیسی ---
23
  def to_english_digits(text):
24
  if not text:
@@ -34,43 +82,38 @@ app = Flask(__name__)
34
 
35
  @app.route('/')
36
  def home():
37
- return "ربات یکپارچه آلفا (نسخه پرو + چت چندرسانه‌ای + پرامپت‌نویس + پادکست + ویرایش عکس) روشن است! 🚀"
38
 
39
  def run_flask():
40
  app.run(host="0.0.0.0", port=7860)
41
 
42
 
43
- # --- ساختار کیبورد آپدیت شده (دقیقاً طبق چیدمان درخواستی شما در ۵ ردیف) ---
44
  MAIN_KEYPAD_DICT = {
45
  "rows": [
46
- # ردیف اول
47
  {
48
  "buttons": [
49
  {"id": "chat_btn", "type": "Simple", "button_text": "چت با هوش مصنوعی 🤖"}
50
  ]
51
  },
52
- # ردیف دوم
53
  {
54
  "buttons": [
55
  {"id": "img_btn", "type": "Simple", "button_text": "ساخت تصاویر🎨"},
56
  {"id": "edit_img_btn", "type": "Simple", "button_text": "ویرایش تصاویر 🪄"}
57
  ]
58
  },
59
- # ردیف سوم
60
  {
61
  "buttons": [
62
  {"id": "podcast_btn", "type": "Simple", "button_text": "ساخت پادکست 🎙️"},
63
  {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا🗣️"}
64
  ]
65
  },
66
- # ردیف چهارم
67
  {
68
  "buttons": [
69
  {"id": "stt_btn", "type": "Simple", "button_text": "فایل صوتی به متن 📝"},
70
  {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل 📁"}
71
  ]
72
  },
73
- # ردیف پنجم
74
  {
75
  "buttons": [
76
  {"id": "account_btn", "type": "Simple", "button_text": "حساب کاربری 👤"},
@@ -81,7 +124,6 @@ MAIN_KEYPAD_DICT = {
81
  "resize_keyboard": True
82
  }
83
 
84
-
85
  # --- تابع ارسال منحصراً برای کیبورد پایین صفحه ---
86
  async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
87
  try:
@@ -105,7 +147,6 @@ async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
105
  # --- 🚨 تابع هوشمند دانلود فایل 🚨 ---
106
  async def helper_download_file(client, msg_obj):
107
  errors = []
108
-
109
  file_id = None
110
  file_obj = None
111
  for attr in ['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']:
@@ -262,7 +303,13 @@ user_last_request_time = {}
262
 
263
  # --- ۱. پردازش چت متنی و چندرسانه‌ای ---
264
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
 
 
 
 
 
265
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
 
266
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
267
  history = user_states[chat_id].get("history", [])
268
  new_parts = []
@@ -321,6 +368,10 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
321
  await send_with_keyboard(client, chat_id, "❌ متأسفانه پاسخی دریافت نشد. (شاید سایز فایل بیش از حد مجاز بوده است)", False)
322
  return
323
 
 
 
 
 
324
  history.append({"role": "model", "parts": [{"text": final_answer}]})
325
  user_states[chat_id]["history"] = history
326
 
@@ -346,9 +397,16 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
346
  except Exception:
347
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
348
 
 
349
  # --- ۲. پردازش ساخت عکس ---
350
  async def process_image(client, chat_id, prompt):
 
 
 
 
 
351
  if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
 
352
  proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما توسط جیمینای...\n(تبدیل به پرامپت حرفه‌ای)", False)
353
  enhanced_prompt = prompt
354
  if GEMINI_KEYS:
@@ -400,6 +458,10 @@ async def process_image(client, chat_id, prompt):
400
 
401
  if not generated_image: return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
402
 
 
 
 
 
403
  try:
404
  file_name = f"image_{random.randint(1000, 999999)}.jpg"
405
  rgb_im = generated_image.convert('RGB')
@@ -411,11 +473,16 @@ async def process_image(client, chat_id, prompt):
411
  if os.path.exists(file_name): os.remove(file_name)
412
  except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
413
 
 
414
  # --- ۲.۵. پردازش ویرایش عکس با FLUX.2-dev ---
415
  async def process_image_edit(client, chat_id, image_bytes, prompt):
 
 
 
 
 
416
  if not HF_TOKENS:
417
- await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
418
- return
419
 
420
  proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال پردازش و اعمال جادوی FLUX.2 روی عکس شما...\n(این فرآیند ممکن است کمی طول بکشد)", False)
421
 
@@ -427,7 +494,6 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
427
  for token in keys_to_try:
428
  try:
429
  hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
430
- # استفاده از متد image_to_image با ارسال دیتای بایت عکس و پرامپت متنی کاربر
431
  generated_image = await hf_client.image_to_image(
432
  image_bytes,
433
  prompt=prompt,
@@ -446,8 +512,11 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
446
  except Exception: pass
447
 
448
  if not generated_image:
449
- await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
450
- return
 
 
 
451
 
452
  try:
453
  file_name = f"edited_flux_{random.randint(1000, 999999)}.jpg"
@@ -465,6 +534,11 @@ async def process_image_edit(client, chat_id, image_bytes, prompt):
465
 
466
  # --- ۳. پردازش ساخت صدا ---
467
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
 
 
 
 
 
468
  try:
469
  proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
470
  payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
@@ -495,6 +569,10 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
495
  except Exception: pass
496
 
497
  if audio_bytes:
 
 
 
 
498
  file_name = f"audio_{random.randint(1000, 999999)}.mp3"
499
  with open(file_name, "wb") as f: f.write(audio_bytes)
500
  await asyncio.sleep(1)
@@ -504,8 +582,14 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
504
  else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
505
  except Exception: traceback.print_exc()
506
 
 
507
  # --- ۳.۵. پردازش پادکست ---
508
  async def process_podcast(client, chat_id, prompt):
 
 
 
 
 
509
  proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست توسط هوش مصنوعی...\n(لطفاً صبور باشید)", False)
510
  available_speakers = []
511
  for num_key, (spk_name, spk_id) in SPEAKERS.items():
@@ -569,6 +653,10 @@ async def process_podcast(client, chat_id, prompt):
569
  combined_audio += audio_segment
570
  except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا (آیا pydub و ffmpeg نصب است؟):\n{str(e)}", True)
571
 
 
 
 
 
572
  file_name = f"final_podcast_{random.randint(1000, 999999)}.mp3"
573
  combined_audio.export(file_name, format="mp3")
574
 
@@ -581,12 +669,19 @@ async def process_podcast(client, chat_id, prompt):
581
 
582
  caption = f"🎧 پادکست شما با موفقیت میکس و ساخته شد!\n\n💡 موضوع شما: {prompt}"
583
  upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", caption)
584
- if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ پادکست با موفقیت ساخته شد اما روبیکا خطای آپلود داد.\n\n`{str(upload_result)[:800]}`", True)
585
  if os.path.exists(file_name): os.remove(file_name)
586
 
 
587
  # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
588
  async def process_stt(client, chat_id, audio_bytes, file_name):
 
 
 
 
 
589
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
 
590
  proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن...", False)
591
  base64_data = base64.b64encode(audio_bytes).decode('utf-8')
592
  mime_type, _ = mimetypes.guess_type(file_name)
@@ -616,12 +711,24 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
616
  if msg_id: await client.delete_messages(chat_id, [msg_id])
617
  except Exception: pass
618
 
619
- if transcribed_text: await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
620
- else: await send_with_keyboard(client, chat_id, f"❌ تبدیل فایل به متن ناموفق بود.", True)
 
 
 
 
 
 
621
 
622
  # --- ۵. پردازش تحلیل فایل مستقل ---
623
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
 
 
 
 
 
624
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False)
 
625
  proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
626
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
627
  mime_type, _ = mimetypes.guess_type(file_name)
@@ -650,8 +757,13 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
650
  if msg_id: await client.delete_messages(chat_id, [msg_id])
651
  except Exception: pass
652
 
653
- if final_answer: await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
654
- else: await send_with_keyboard(client, chat_id, "❌ پاسخی دریافت نشد.", True)
 
 
 
 
 
655
 
656
 
657
  # --- تنظیمات ربات روبیکا ---
@@ -666,7 +778,6 @@ else:
666
  current_time = time.time()
667
 
668
  # 🛡 ۱. فیلتر پیام‌های قدیمی (Backlog) در زمان ری‌استارت اسپیس 🛡
669
- # اگر از زمان روشن شدن ربات کمتر از 8 ثانیه گذشته، پیام را نادیده بگیر
670
  if current_time - BOT_STARTUP_TIME < 8.0:
671
  return
672
 
@@ -695,9 +806,9 @@ else:
695
  processed_message_ids.add(unique_msg_key)
696
  if len(processed_message_ids) > 5000: processed_message_ids.clear()
697
 
698
- # 🛡 سیستم محدودکننده سرعت کاربر (Rate Limit) برای همه پیام‌ها (حتی استارت) 🛡
699
  last_req_time = user_last_request_time.get(chat_id, 0)
700
- if current_time - last_req_time < 1.5: # فاصله 1.5 ثانیه بین هر پیام الزامی است
701
  return
702
  user_last_request_time[chat_id] = current_time
703
 
@@ -734,21 +845,24 @@ else:
734
  await send_with_keyboard(client, chat_id, "سلام! به ربات هوشمند آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
735
  return
736
 
737
- # --- حساب کاربری ---
738
  if user_text_str in ["/account", "حساب کاربری 👤"]:
 
739
  account_profile = f"""👤 **اطلاعات حساب کاربری شما**
740
 
741
  🔹 **شناسه یکتا:** `{chat_id}`
742
  🔹 **وضعیت اشتراک:** 🥉 نسخه رایگان (آزمایشی)
743
 
744
- 📊 **سهمیه روزانه شما در نسخه رایگان:**
745
- - 💬 چت هوشمند: ۳۰ پیام
746
- - 🎨 ساخت عکس: ۵ تصویر
747
- - 🪄 ویرایش عکس پیشرفته: ۳ تصویر
748
- - 🎙 ساخت پادکست: ۱ برنامه
749
- - 🗣 تبدیل متن به صدا: ۵ فایل
 
 
750
 
751
- *نکته: در آینده با ارتقا به نسخه آلفا پرو می‌توانید تمام این محدودیت‌ها را بردارید.* 🚀"""
752
  await send_with_keyboard(client, chat_id, account_profile, True)
753
  return
754
 
@@ -834,7 +948,6 @@ else:
834
  user_states[chat_id]["text"] = user_text_str
835
  user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
836
 
837
- # بازگرداندن متن کامل لیست گویندگان
838
  speakers_menu = """✅ متن شما ذخیره شد.
839
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
840
  1. شهاب | 2. آوا | 3. نوید
@@ -851,7 +964,6 @@ else:
851
  return
852
 
853
  elif current_mode == "tts_waiting_for_speaker":
854
- # تبدیل اعداد فارسی/عربی احتمالی به انگلیسی
855
  normalized_text = to_english_digits(user_text_str)
856
 
857
  if normalized_text.isdigit() and normalized_text in SPEAKERS:
@@ -903,5 +1015,5 @@ else:
903
  if __name__ == "__main__":
904
  threading.Thread(target=run_flask, daemon=True).start()
905
  if bot_token:
906
- print("ربات آلفا روشن شد...")
907
  bot.run()
 
8
  import base64
9
  import mimetypes
10
  import io
11
+ import json
12
+ import datetime
13
  from flask import Flask
14
  from rubpy.bot import BotClient, filters
15
 
 
21
  # --- ثبت زمان روشن شدن ربات برای جلوگیری از پرتاب پیام‌های قدیمی ---
22
  BOT_STARTUP_TIME = time.time()
23
 
24
+ # --- سیستم دیتابیس حساب کاربری و مدیریت اعتبار ---
25
+ DB_FILE = "users_db.json"
26
+ db_lock = threading.Lock()
27
+
28
+ def load_db():
29
+ if os.path.exists(DB_FILE):
30
+ try:
31
+ with open(DB_FILE, "r", encoding="utf-8") as f:
32
+ return json.load(f)
33
+ except Exception:
34
+ return {}
35
+ return {}
36
+
37
+ def save_db(db_data):
38
+ with db_lock:
39
+ try:
40
+ with open(DB_FILE, "w", encoding="utf-8") as f:
41
+ json.dump(db_data, f, ensure_ascii=False, indent=4)
42
+ except Exception as e:
43
+ print("خطا در ذخیره دیتابیس:", e)
44
+
45
+ user_credits_db = load_db()
46
+
47
+ def get_user_credits(chat_id):
48
+ str_chat_id = str(chat_id)
49
+ today_str = datetime.date.today().isoformat()
50
+
51
+ if str_chat_id not in user_credits_db:
52
+ user_credits_db[str_chat_id] = {}
53
+
54
+ user_data = user_credits_db[str_chat_id]
55
+
56
+ # بازنشانی خودکار سهمیه روزانه
57
+ if user_data.get("last_reset") != today_str:
58
+ user_data["last_reset"] = today_str
59
+ user_data["chat"] = 30
60
+ user_data["image"] = 5
61
+ user_data["edit_image"] = 3
62
+ user_data["podcast"] = 1
63
+ user_data["tts"] = 5
64
+ user_data["file"] = 5
65
+ user_data["stt"] = 5
66
+ save_db(user_credits_db)
67
+
68
+ return user_data
69
+
70
  # --- تابع تبدیل اعداد فارسی/عربی به انگلیسی ---
71
  def to_english_digits(text):
72
  if not text:
 
82
 
83
  @app.route('/')
84
  def home():
85
+ return "ربات یکپارچه آلفا (نسخه پرو + دیتابیس اعتبار + پادکست + ویرایش عکس) روشن است! 🚀"
86
 
87
  def run_flask():
88
  app.run(host="0.0.0.0", port=7860)
89
 
90
 
91
+ # --- ساختار کیبورد آپدیت شده (۵ ردیف) ---
92
  MAIN_KEYPAD_DICT = {
93
  "rows": [
 
94
  {
95
  "buttons": [
96
  {"id": "chat_btn", "type": "Simple", "button_text": "چت با هوش مصنوعی 🤖"}
97
  ]
98
  },
 
99
  {
100
  "buttons": [
101
  {"id": "img_btn", "type": "Simple", "button_text": "ساخت تصاویر🎨"},
102
  {"id": "edit_img_btn", "type": "Simple", "button_text": "ویرایش تصاویر 🪄"}
103
  ]
104
  },
 
105
  {
106
  "buttons": [
107
  {"id": "podcast_btn", "type": "Simple", "button_text": "ساخت پادکست 🎙️"},
108
  {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا🗣️"}
109
  ]
110
  },
 
111
  {
112
  "buttons": [
113
  {"id": "stt_btn", "type": "Simple", "button_text": "فایل صوتی به متن 📝"},
114
  {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل 📁"}
115
  ]
116
  },
 
117
  {
118
  "buttons": [
119
  {"id": "account_btn", "type": "Simple", "button_text": "حساب کاربری 👤"},
 
124
  "resize_keyboard": True
125
  }
126
 
 
127
  # --- تابع ارسال منحصراً برای کیبورد پایین صفحه ---
128
  async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
129
  try:
 
147
  # --- 🚨 تابع هوشمند دانلود فایل 🚨 ---
148
  async def helper_download_file(client, msg_obj):
149
  errors = []
 
150
  file_id = None
151
  file_obj = None
152
  for attr in ['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']:
 
303
 
304
  # --- ۱. پردازش چت متنی و چندرسانه‌ای ---
305
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
306
+ str_chat_id = str(chat_id)
307
+ creds = get_user_credits(str_chat_id)
308
+ if creds["chat"] <= 0:
309
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار پیام‌های چت شما برای امروز تمام شده است.", False)
310
+
311
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
312
+
313
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
314
  history = user_states[chat_id].get("history", [])
315
  new_parts = []
 
368
  await send_with_keyboard(client, chat_id, "❌ متأسفانه پاسخی دریافت نشد. (شاید سایز فایل بیش از حد مجاز بوده است)", False)
369
  return
370
 
371
+ # کسر اعتبار بعد از موفقیت
372
+ user_credits_db[str_chat_id]["chat"] -= 1
373
+ save_db(user_credits_db)
374
+
375
  history.append({"role": "model", "parts": [{"text": final_answer}]})
376
  user_states[chat_id]["history"] = history
377
 
 
397
  except Exception:
398
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
399
 
400
+
401
  # --- ۲. پردازش ساخت عکس ---
402
  async def process_image(client, chat_id, prompt):
403
+ str_chat_id = str(chat_id)
404
+ creds = get_user_credits(str_chat_id)
405
+ if creds["image"] <= 0:
406
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت عکس روزانه شما تمام شده است.", False)
407
+
408
  if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
409
+
410
  proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما توسط جیمینای...\n(تبدیل به پرامپت حرفه‌ای)", False)
411
  enhanced_prompt = prompt
412
  if GEMINI_KEYS:
 
458
 
459
  if not generated_image: return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
460
 
461
+ # کسر اعتبار
462
+ user_credits_db[str_chat_id]["image"] -= 1
463
+ save_db(user_credits_db)
464
+
465
  try:
466
  file_name = f"image_{random.randint(1000, 999999)}.jpg"
467
  rgb_im = generated_image.convert('RGB')
 
473
  if os.path.exists(file_name): os.remove(file_name)
474
  except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
475
 
476
+
477
  # --- ۲.۵. پردازش ویرایش عکس با FLUX.2-dev ---
478
  async def process_image_edit(client, chat_id, image_bytes, prompt):
479
+ str_chat_id = str(chat_id)
480
+ creds = get_user_credits(str_chat_id)
481
+ if creds["edit_image"] <= 0:
482
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار ویرایش عکس روزانه شما تمام شده است.", False)
483
+
484
  if not HF_TOKENS:
485
+ return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
 
486
 
487
  proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال پردازش و اعمال جادوی FLUX.2 روی عکس شما...\n(این فرآیند ممکن است کمی طول بکشد)", False)
488
 
 
494
  for token in keys_to_try:
495
  try:
496
  hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
 
497
  generated_image = await hf_client.image_to_image(
498
  image_bytes,
499
  prompt=prompt,
 
512
  except Exception: pass
513
 
514
  if not generated_image:
515
+ return await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
516
+
517
+ # کسر اعتبار
518
+ user_credits_db[str_chat_id]["edit_image"] -= 1
519
+ save_db(user_credits_db)
520
 
521
  try:
522
  file_name = f"edited_flux_{random.randint(1000, 999999)}.jpg"
 
534
 
535
  # --- ۳. پردازش ساخت صدا ---
536
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
537
+ str_chat_id = str(chat_id)
538
+ creds = get_user_credits(str_chat_id)
539
+ if creds["tts"] <= 0:
540
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل متن به صدای شما تمام شده است.", False)
541
+
542
  try:
543
  proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
544
  payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
 
569
  except Exception: pass
570
 
571
  if audio_bytes:
572
+ # کسر اعتبار
573
+ user_credits_db[str_chat_id]["tts"] -= 1
574
+ save_db(user_credits_db)
575
+
576
  file_name = f"audio_{random.randint(1000, 999999)}.mp3"
577
  with open(file_name, "wb") as f: f.write(audio_bytes)
578
  await asyncio.sleep(1)
 
582
  else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
583
  except Exception: traceback.print_exc()
584
 
585
+
586
  # --- ۳.۵. پردازش پادکست ---
587
  async def process_podcast(client, chat_id, prompt):
588
+ str_chat_id = str(chat_id)
589
+ creds = get_user_credits(str_chat_id)
590
+ if creds["podcast"] <= 0:
591
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت پادکست روزانه شما تمام شده است.", False)
592
+
593
  proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست توسط هوش مصنوعی...\n(لطفاً صبور باشید)", False)
594
  available_speakers = []
595
  for num_key, (spk_name, spk_id) in SPEAKERS.items():
 
653
  combined_audio += audio_segment
654
  except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا (آیا pydub و ffmpeg نصب است؟):\n{str(e)}", True)
655
 
656
+ # کسر اعتبار در صورت اتمام موفق میکس
657
+ user_credits_db[str_chat_id]["podcast"] -= 1
658
+ save_db(user_credits_db)
659
+
660
  file_name = f"final_podcast_{random.randint(1000, 999999)}.mp3"
661
  combined_audio.export(file_name, format="mp3")
662
 
 
669
 
670
  caption = f"🎧 پادکست شما با موفقیت میکس و ساخته شد!\n\n💡 موضوع شما: {prompt}"
671
  upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", caption)
672
+ if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ پادکست ساخته شد اما روبیکا خطای آپلود داد.\n\n`{str(upload_result)[:800]}`", True)
673
  if os.path.exists(file_name): os.remove(file_name)
674
 
675
+
676
  # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
677
  async def process_stt(client, chat_id, audio_bytes, file_name):
678
+ str_chat_id = str(chat_id)
679
+ creds = get_user_credits(str_chat_id)
680
+ if creds["stt"] <= 0:
681
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل صدا به متن شما تمام شده است.", False)
682
+
683
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
684
+
685
  proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن...", False)
686
  base64_data = base64.b64encode(audio_bytes).decode('utf-8')
687
  mime_type, _ = mimetypes.guess_type(file_name)
 
711
  if msg_id: await client.delete_messages(chat_id, [msg_id])
712
  except Exception: pass
713
 
714
+ if transcribed_text:
715
+ # کسر اعتبار
716
+ user_credits_db[str_chat_id]["stt"] -= 1
717
+ save_db(user_credits_db)
718
+ await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
719
+ else:
720
+ await send_with_keyboard(client, chat_id, f"❌ تبدیل فایل به متن ناموفق بود.", True)
721
+
722
 
723
  # --- ۵. پردازش تحلیل فایل مستقل ---
724
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
725
+ str_chat_id = str(chat_id)
726
+ creds = get_user_credits(str_chat_id)
727
+ if creds["file"] <= 0:
728
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار تحلیل فایل روزانه شما تمام شده است.", False)
729
+
730
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False)
731
+
732
  proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
733
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
734
  mime_type, _ = mimetypes.guess_type(file_name)
 
757
  if msg_id: await client.delete_messages(chat_id, [msg_id])
758
  except Exception: pass
759
 
760
+ if final_answer:
761
+ # کسر اعتبار
762
+ user_credits_db[str_chat_id]["file"] -= 1
763
+ save_db(user_credits_db)
764
+ await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
765
+ else:
766
+ await send_with_keyboard(client, chat_id, "❌ پاسخی دریافت نشد.", True)
767
 
768
 
769
  # --- تنظیمات ربات روبیکا ---
 
778
  current_time = time.time()
779
 
780
  # 🛡 ۱. فیلتر پیام‌های قدیمی (Backlog) در زمان ری‌استارت اسپیس 🛡
 
781
  if current_time - BOT_STARTUP_TIME < 8.0:
782
  return
783
 
 
806
  processed_message_ids.add(unique_msg_key)
807
  if len(processed_message_ids) > 5000: processed_message_ids.clear()
808
 
809
+ # 🛡 سیستم محدودکننده سرعت کاربر (Rate Limit) 🛡
810
  last_req_time = user_last_request_time.get(chat_id, 0)
811
+ if current_time - last_req_time < 1.5:
812
  return
813
  user_last_request_time[chat_id] = current_time
814
 
 
845
  await send_with_keyboard(client, chat_id, "سلام! به ربات هوشمند آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
846
  return
847
 
848
+ # --- حساب کاربری پویا و دقیق ---
849
  if user_text_str in ["/account", "حساب کاربری 👤"]:
850
+ creds = get_user_credits(chat_id)
851
  account_profile = f"""👤 **اطلاعات حساب کاربری شما**
852
 
853
  🔹 **شناسه یکتا:** `{chat_id}`
854
  🔹 **وضعیت اشتراک:** 🥉 نسخه رایگان (آزمایشی)
855
 
856
+ 📊 **سهمیه باقی‌مانده شما در امروز:**
857
+ - 💬 چت هوشمند: {creds['chat']} پیام
858
+ - 🎨 ساخت عکس: {creds['image']} تصویر
859
+ - 🪄 ویرایش عکس پیشرفته: {creds['edit_image']} تصویر
860
+ - 🎙 ساخت پادکست: {creds['podcast']} برنامه
861
+ - 🗣 تبدیل متن به صدا: {creds['tts']} فایل
862
+ - 📁 تحلیل فایل: {creds['file']} فایل
863
+ - 📝 تبدیل صدا به متن: {creds['stt']} فایل
864
 
865
+ *نکته: اعتبار شما هر روز ساعت ۰۰:۰۰ به صورت خودکار شارژ می‌شود. با ارتقا به نسخه آلفا پرو می‌توانید تمام این محدودیت‌ها را بردارید.* 🚀"""
866
  await send_with_keyboard(client, chat_id, account_profile, True)
867
  return
868
 
 
948
  user_states[chat_id]["text"] = user_text_str
949
  user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
950
 
 
951
  speakers_menu = """✅ متن شما ذخیره شد.
952
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
953
  1. شهاب | 2. آوا | 3. نوید
 
964
  return
965
 
966
  elif current_mode == "tts_waiting_for_speaker":
 
967
  normalized_text = to_english_digits(user_text_str)
968
 
969
  if normalized_text.isdigit() and normalized_text in SPEAKERS:
 
1015
  if __name__ == "__main__":
1016
  threading.Thread(target=run_flask, daemon=True).start()
1017
  if bot_token:
1018
+ print("ربات آلفا با موفقیت به همراه دیتابیس روشن شد...")
1019
  bot.run()