Opera8 commited on
Commit
d66724a
·
verified ·
1 Parent(s): f901639

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +143 -102
main.py CHANGED
@@ -16,6 +16,16 @@ from huggingface_hub import AsyncInferenceClient
16
  from PIL import Image
17
  from pydub import AudioSegment
18
 
 
 
 
 
 
 
 
 
 
 
19
  # --- تنظیمات وب سرور ---
20
  app = Flask(__name__)
21
 
@@ -27,7 +37,7 @@ def run_flask():
27
  app.run(host="0.0.0.0", port=7860)
28
 
29
 
30
- # --- ساختار کیبورد آپدیت شده (دقیقاً طبق چیدمان درخواستی شما) ---
31
  MAIN_KEYPAD_DICT = {
32
  "rows": [
33
  # ردیف اول
@@ -247,59 +257,7 @@ processed_message_ids = set()
247
  user_last_request_time = {}
248
 
249
 
250
- # --- بخش پردازش ویرایش عکس با FLUX.2-dev ---
251
- async def process_image_edit(client, chat_id, image_bytes, prompt):
252
- if not HF_TOKENS:
253
- await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
254
- return
255
-
256
- proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال پردازش و اعمال جادوی FLUX.2 روی عکس شما...\n(این فرآیند ممکن است کمی طول بکشد)", False)
257
-
258
- keys_to_try = HF_TOKENS.copy()
259
- random.shuffle(keys_to_try)
260
- generated_image = None
261
- last_error_log = "سرور پاسخ نداد."
262
-
263
- for token in keys_to_try:
264
- try:
265
- hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
266
- # استفاده از متد image_to_image با ارسال دیتای بایت عکس و پرامپت متنی کاربر
267
- generated_image = await hf_client.image_to_image(
268
- image_bytes,
269
- prompt=prompt,
270
- model="black-forest-labs/FLUX.2-dev"
271
- )
272
- break
273
- except Exception as e:
274
- last_error_log = str(e)
275
- continue
276
-
277
- try:
278
- if proc_msg:
279
- msg_id = getattr(proc_msg, 'message_id', None)
280
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
281
- if msg_id: await client.delete_messages(chat_id, [msg_id])
282
- except Exception: pass
283
-
284
- if not generated_image:
285
- await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
286
- return
287
-
288
- try:
289
- file_name = f"edited_flux_{random.randint(1000, 999999)}.jpg"
290
- rgb_im = generated_image.convert('RGB')
291
- rgb_im.save(file_name, format="JPEG", quality=100)
292
- await asyncio.sleep(1)
293
- caption_text = f"🪄 ویرایش عکس با هوش مصنوعی Flux.2 انجام شد!\n\n✨ تغییرات خواسته شده: {prompt}"
294
- upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
295
- if upload_result is not True:
296
- await send_with_keyboard(client, chat_id, f"❌ عکس ساخته شد اما خطا در ارسال به روبیکا رخ داد:\n`{str(upload_result)[:800]}`", True)
297
- if os.path.exists(file_name): os.remove(file_name)
298
- except Exception as e:
299
- await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
300
-
301
-
302
- # --- پردازش‌های قبلی ---
303
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
304
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
305
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
@@ -312,7 +270,15 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
312
  if file_bytes and file_name:
313
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
314
  mime_type, _ = mimetypes.guess_type(file_name)
315
- if not mime_type: mime_type = "image/jpeg"
 
 
 
 
 
 
 
 
316
  new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
317
 
318
  if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
@@ -349,7 +315,7 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
349
 
350
  if not final_answer:
351
  if history and history[-1]["role"] == "user": history.pop()
352
- await send_with_keyboard(client, chat_id, "❌ متأسفانه پاسخی دریافت نشد.", False)
353
  return
354
 
355
  history.append({"role": "model", "parts": [{"text": final_answer}]})
@@ -377,14 +343,15 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
377
  except Exception:
378
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
379
 
 
380
  async def process_image(client, chat_id, prompt):
381
- if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکن‌ها تنظیم نشده‌اند.", False)
382
  proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما توسط جیمینای...\n(تبدیل به پرامپت حرفه‌ای)", False)
383
  enhanced_prompt = prompt
384
  if GEMINI_KEYS:
385
  keys_to_try_gemini = GEMINI_KEYS.copy()
386
  random.shuffle(keys_to_try_gemini)
387
- 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 keywords. Return ONLY the final English prompt string.\nUser input: {prompt}"
388
  async with aiohttp.ClientSession() as session:
389
  for key in keys_to_try_gemini:
390
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
@@ -437,10 +404,63 @@ async def process_image(client, chat_id, prompt):
437
  await asyncio.sleep(1)
438
  caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n✨ ایده اولیه: {prompt}"
439
  upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
440
- if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ خطا در آپلود:\n`{str(upload_result)[:800]}`", True)
441
  if os.path.exists(file_name): os.remove(file_name)
442
  except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
443
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
445
  try:
446
  proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
@@ -481,8 +501,9 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
481
  else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
482
  except Exception: traceback.print_exc()
483
 
 
484
  async def process_podcast(client, chat_id, prompt):
485
- proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست...\n(لطفاً صبور باشید)", False)
486
  available_speakers = []
487
  for num_key, (spk_name, spk_id) in SPEAKERS.items():
488
  gender = "male" if "مرد" in spk_name else "female"
@@ -494,9 +515,9 @@ async def process_podcast(client, chat_id, prompt):
494
  async with aiohttp.ClientSession() as session:
495
  try:
496
  async with session.post(url_create, json=payload_create, timeout=60) as resp:
497
- if resp.status != 202: return await send_with_keyboard(client, chat_id, f"❌ خطا: وضعیت {resp.status}", True)
498
  task_id = (await resp.json()).get("task_id")
499
- except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا اتصال:\n{str(e)}", True)
500
 
501
  url_status = f"https://ezmarynoori-podgen.hf.space/api/podcast-status/{task_id}"
502
  script_data = None
@@ -510,10 +531,10 @@ async def process_podcast(client, chat_id, prompt):
510
  script_data = status_data.get("data", {}).get("script", [])
511
  break
512
  elif status_data.get("status") == "failed":
513
- return await send_with_keyboard(client, chat_id, "❌ هوش مصنوعی نتوانست سناریو بنویسد.", True)
514
  except Exception: pass
515
 
516
- if not script_data: return await send_with_keyboard(client, chat_id, "❌ پایان زمان انتظار برای نوشتن سناریو.", True)
517
 
518
  try:
519
  if proc_msg:
@@ -522,7 +543,7 @@ async def process_podcast(client, chat_id, prompt):
522
  if msg_id: await client.delete_messages(chat_id, [msg_id])
523
  except: pass
524
 
525
- proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال میکس (شامل {len(script_data)} نوبت صحبت)...\nزمان‌بر است...", False)
526
 
527
  combined_audio = AudioSegment.empty()
528
  url_generate = "https://ezmarynoori-podgen.hf.space/api/generate"
@@ -538,12 +559,12 @@ async def process_podcast(client, chat_id, prompt):
538
  break
539
  except Exception: await asyncio.sleep(2)
540
 
541
- if not chunk_audio_bytes: return await send_with_keyboard(client, chat_id, f"❌ خطا در بخش {index+1}", True)
542
 
543
  try:
544
  audio_segment = AudioSegment.from_file(io.BytesIO(chunk_audio_bytes))
545
  combined_audio += audio_segment
546
- except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا میکس:\n{str(e)}", True)
547
 
548
  file_name = f"final_podcast_{random.randint(1000, 999999)}.mp3"
549
  combined_audio.export(file_name, format="mp3")
@@ -555,14 +576,15 @@ async def process_podcast(client, chat_id, prompt):
555
  if msg_id: await client.delete_messages(chat_id, [msg_id])
556
  except: pass
557
 
558
- caption = f"🎧 پادکست شما میکس شد!\n\n💡 موضوع: {prompt}"
559
  upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", caption)
560
- if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ خطای آپلود روبیکا.\n\n`{str(upload_result)[:800]}`", True)
561
  if os.path.exists(file_name): os.remove(file_name)
562
 
 
563
  async def process_stt(client, chat_id, audio_bytes, file_name):
564
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید تنظیم نشده", False)
565
- proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال پیاده‌سازی متن...", False)
566
  base64_data = base64.b64encode(audio_bytes).decode('utf-8')
567
  mime_type, _ = mimetypes.guess_type(file_name)
568
  if not mime_type: mime_type = "audio/ogg"
@@ -570,7 +592,7 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
570
  keys_to_try = GEMINI_KEYS.copy()
571
  random.shuffle(keys_to_try)
572
  transcribed_text = None
573
- prompt = "این فایل صوتی/تصویری را دقیق گوش بده و صحبت‌ها را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
574
 
575
  async with aiohttp.ClientSession() as session:
576
  for key in keys_to_try:
@@ -591,11 +613,12 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
591
  if msg_id: await client.delete_messages(chat_id, [msg_id])
592
  except Exception: pass
593
 
594
- if transcribed_text: await send_with_keyboard(client, chat_id, f"📝 **متن:**\n\n{transcribed_text}", True)
595
- else: await send_with_keyboard(client, chat_id, f"❌ تبدیل ناموفق", True)
596
 
 
597
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
598
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید تنظیم نیست.", False)
599
  proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
600
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
601
  mime_type, _ = mimetypes.guess_type(file_name)
@@ -624,7 +647,7 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
624
  if msg_id: await client.delete_messages(chat_id, [msg_id])
625
  except Exception: pass
626
 
627
- if final_answer: await send_with_keyboard(client, chat_id, f"💡 **تحلیل:**\n\n{final_answer}", True)
628
  else: await send_with_keyboard(client, chat_id, "❌ پاسخی دریافت نشد.", True)
629
 
630
 
@@ -699,10 +722,10 @@ else:
699
 
700
  if user_text_str in ["/start", "سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
701
  user_states[chat_id] = {"mode": None, "text": "", "history": [], "file_bytes": None, "file_name": None}
702
- await send_with_keyboard(client, chat_id, "سلام کاربر عزیز! به ربات هوشمند آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، یکی از بخش‌های زیر را انتخاب کنید:", True)
703
  return
704
 
705
- # --- شخصی‌سازی حساب کاربری با شناسه چت (داینامیک) ---
706
  if user_text_str in ["/account", "حساب کاربری 👤"]:
707
  account_profile = f"""👤 **اطلاعات حساب کاربری شما**
708
 
@@ -722,44 +745,44 @@ else:
722
 
723
  if user_text_str in ["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
724
  user_states[chat_id] = {"mode": "chat", "text": "", "history": []}
725
- await send_with_keyboard(client, chat_id, "💬 وارد بخش **چت هوشمند** شدید.\nسوالی بپرسید تا جواب بدهم:", True)
726
  return
727
 
728
  if user_text_str in ["/image", "🎨 عکس", "ساخت تصاویر🎨"]:
729
  user_states[chat_id] = {"mode": "image_waiting_for_text", "text": "", "history": []}
730
- await send_with_keyboard(client, chat_id, "🎨 وارد بخش **ساخت عکس** شدید.\nمتن خود را بفرستید:", True)
731
  return
732
 
733
  if user_text_str in ["/edit_image", "ویرایش تصاویر 🪄"]:
734
  user_states[chat_id] = {"mode": "image_edit_waiting_for_image", "text": "", "history": [], "file_bytes": None, "file_name": None}
735
- await send_with_keyboard(client, chat_id, "🪄 به بخش **ویرایش عکس (Flux.2)** خوش آمدید.\n\nلطفاً ابتدا عکسی که می‌خواهید ویرایش کنید را بفرستید:", True)
736
  return
737
 
738
  if user_text_str in ["/tts", "🎙️ صدا", "تبدیل متن به صدا🗣️"]:
739
  user_states[chat_id] = {"mode": "tts_waiting_for_text", "text": "", "history": []}
740
- await send_with_keyboard(client, chat_id, "🎙️ وارد بخش **تبدیل متن به صدا** شدید.\nمتن خود را بفرستید:", True)
741
  return
742
 
743
  if user_text_str in ["/podcast", "📻 پادکست", "ساخت پادکست 🎙️"]:
744
  user_states[chat_id] = {"mode": "podcast_waiting_for_topic", "text": "", "history": []}
745
- await send_with_keyboard(client, chat_id, "📻 وارد بخش **ساخت پادکست** شدید.\nموضوع پادکست را بفرستید:", True)
746
  return
747
 
748
  if user_text_str in ["/file", "تحلیل فایل ��"]:
749
  user_states[chat_id] = {"mode": "file_waiting_for_file", "text": "", "history": [], "file_bytes": None, "file_name": None}
750
- await send_with_keyboard(client, chat_id, "📁 وارد بخش **تحلیل فایل** شدید.\nفایل خود را ارسال کنید:", True)
751
  return
752
 
753
  if user_text_str in ["/stt", "فایل صوتی به متن 📝"]:
754
  user_states[chat_id] = {"mode": "stt_waiting_for_audio", "text": "", "history": []}
755
- await send_with_keyboard(client, chat_id, "📝 وارد بخش **تبدیل صدا به متن** شدید.\nفایل خود را بفرستید:", True)
756
  return
757
 
758
  current_mode = user_states[chat_id].get("mode")
759
 
760
  if current_mode is None:
761
  if is_file: pass
762
- elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک بخش را از کیبورد پایین انتخاب کنید:", True)
763
  return
764
 
765
  elif current_mode == "chat":
@@ -768,7 +791,7 @@ else:
768
  try:
769
  file_bytes = await helper_download_file(client, msg_obj)
770
  asyncio.create_task(process_gemini(client, chat_id, user_text_str, file_bytes=file_bytes, file_name=file_name))
771
- except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا!\n{str(dl_err)}", False)
772
  elif user_text_str: asyncio.create_task(process_gemini(client, chat_id, user_text_str))
773
  return
774
 
@@ -784,7 +807,7 @@ else:
784
  user_states[chat_id]["file_bytes"] = file_bytes
785
  user_states[chat_id]["mode"] = "image_edit_waiting_for_prompt"
786
  await send_with_keyboard(client, chat_id, "✅ عکس با موفقیت دریافت شد.\n\nحالا دستور خود را به صورت متنی تایپ کنید.\nمثال: یک کلاه قرمز روی سر این گربه بگذار.", False)
787
- except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
788
  return
789
 
790
  elif current_mode == "image_edit_waiting_for_prompt":
@@ -798,45 +821,63 @@ else:
798
 
799
  elif current_mode == "tts_waiting_for_text":
800
  if user_text_str:
801
- if len(user_text_str) > 2500: return await send_with_keyboard(client, chat_id, "⚠️ متن خیلی طولانی است.", False)
802
  user_states[chat_id]["text"] = user_text_str
803
  user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
804
- await send_with_keyboard(client, chat_id, "✅ متن ذخیره شد.\nلطفاً **شماره** گوینده (بین 1 تا 30) را بفرستید:", False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  return
806
 
807
  elif current_mode == "tts_waiting_for_speaker":
808
- if user_text_str.isdigit() and user_text_str in SPEAKERS:
809
- spk_name, spk_id = SPEAKERS[user_text_str]
 
 
 
810
  txt = user_states[chat_id]["text"]
811
  user_states[chat_id]["mode"] = "tts_waiting_for_text"
812
  asyncio.create_task(process_tts(client, chat_id, txt, spk_id, spk_name))
813
- else: await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر!", False)
 
814
  return
815
 
816
  elif current_mode == "podcast_waiting_for_topic":
817
  if user_text_str: asyncio.create_task(process_podcast(client, chat_id, user_text_str))
818
- else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع را متنی بفرستید.", False)
819
  return
820
 
821
  elif current_mode == "stt_waiting_for_audio":
822
- if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً فایل بفرستید.", False)
823
- await send_with_keyboard(client, chat_id, "📥 در حال دانلود...", False)
824
  try:
825
  audio_bytes = await helper_download_file(client, msg_obj)
826
  asyncio.create_task(process_stt(client, chat_id, audio_bytes, file_name))
827
- except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا!\n{str(dl_err)}", False)
828
  return
829
 
830
  elif current_mode == "file_waiting_for_file":
831
- if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ فایل بفرستید.", False)
832
- await send_with_keyboard(client, chat_id, "📥 دریافت فایل...", False)
833
  try:
834
  file_bytes = await helper_download_file(client, msg_obj)
835
  user_states[chat_id]["file_bytes"] = file_bytes
836
  user_states[chat_id]["file_name"] = file_name
837
  user_states[chat_id]["mode"] = "file_waiting_for_prompt"
838
- await send_with_keyboard(client, chat_id, "✅ دریافت شد.\nچگونه تحلیل شود؟", False)
839
- except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا!\n{str(dl_err)}", False)
840
  return
841
 
842
  elif current_mode == "file_waiting_for_prompt":
@@ -845,7 +886,7 @@ else:
845
  saved_name = user_states[chat_id].get("file_name", "file.jpeg")
846
  user_states[chat_id]["mode"] = "file_waiting_for_file"
847
  asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str))
848
- else: await send_with_keyboard(client, chat_id, "⚠️ متن بفرستید.", False)
849
  return
850
 
851
  except Exception: traceback.print_exc()
 
16
  from PIL import Image
17
  from pydub import AudioSegment
18
 
19
+ # --- تابع تبدیل اعداد فارسی/عربی به انگلیسی ---
20
+ def to_english_digits(text):
21
+ if not text:
22
+ return text
23
+ persian_digits = '۰۱۲۳۴۵۶۷۸۹'
24
+ arabic_digits = '٠١٢٣٤٥٦٧٨٩'
25
+ english_digits = '0123456789'
26
+ translation_table = str.maketrans(persian_digits + arabic_digits, english_digits * 2)
27
+ return str(text).translate(translation_table)
28
+
29
  # --- تنظیمات وب سرور ---
30
  app = Flask(__name__)
31
 
 
37
  app.run(host="0.0.0.0", port=7860)
38
 
39
 
40
+ # --- ساختار کیبورد آپدیت شده (دقیقاً طبق چیدمان درخواستی شما در ۵ ردیف) ---
41
  MAIN_KEYPAD_DICT = {
42
  "rows": [
43
  # ردیف اول
 
257
  user_last_request_time = {}
258
 
259
 
260
+ # --- ۱. پردازش چت متنی و چندرسانه‌ای ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
262
  if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
263
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
 
270
  if file_bytes and file_name:
271
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
272
  mime_type, _ = mimetypes.guess_type(file_name)
273
+ if not mime_type:
274
+ if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg"
275
+ elif file_name.endswith('.png'): mime_type = "image/png"
276
+ elif file_name.endswith('.pdf'): mime_type = "application/pdf"
277
+ elif file_name.endswith('.mp4'): mime_type = "video/mp4"
278
+ elif file_name.endswith('.mp3'): mime_type = "audio/mp3"
279
+ elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg"
280
+ elif file_name.endswith('.wav'): mime_type = "audio/wav"
281
+ else: mime_type = "image/jpeg"
282
  new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
283
 
284
  if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
 
315
 
316
  if not final_answer:
317
  if history and history[-1]["role"] == "user": history.pop()
318
+ await send_with_keyboard(client, chat_id, "❌ متأسفانه پاسخی دریافت نشد. (شاید سایز فایل بیش از حد مجاز بوده است)", False)
319
  return
320
 
321
  history.append({"role": "model", "parts": [{"text": final_answer}]})
 
343
  except Exception:
344
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
345
 
346
+ # --- ۲. پردازش ساخت عکس ---
347
  async def process_image(client, chat_id, prompt):
348
+ if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
349
  proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما توسط جیمینای...\n(تبدیل به پرامپت حرفه‌ای)", False)
350
  enhanced_prompt = prompt
351
  if GEMINI_KEYS:
352
  keys_to_try_gemini = GEMINI_KEYS.copy()
353
  random.shuffle(keys_to_try_gemini)
354
+ 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}"
355
  async with aiohttp.ClientSession() as session:
356
  for key in keys_to_try_gemini:
357
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
 
404
  await asyncio.sleep(1)
405
  caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n✨ ایده اولیه: {prompt}"
406
  upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
407
+ if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ خطا در آپلود روبیکا:\n`{str(upload_result)[:800]}`", True)
408
  if os.path.exists(file_name): os.remove(file_name)
409
  except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
410
 
411
+ # --- ۲.۵. پردازش ویرایش عکس با FLUX.2-dev ---
412
+ async def process_image_edit(client, chat_id, image_bytes, prompt):
413
+ if not HF_TOKENS:
414
+ await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
415
+ return
416
+
417
+ proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال پردازش و اعمال جادوی FLUX.2 روی عکس شما...\n(این فرآیند ممکن است کمی طول بکشد)", False)
418
+
419
+ keys_to_try = HF_TOKENS.copy()
420
+ random.shuffle(keys_to_try)
421
+ generated_image = None
422
+ last_error_log = "سرور پاسخ نداد."
423
+
424
+ for token in keys_to_try:
425
+ try:
426
+ hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
427
+ # استفاده از متد image_to_image با ارسال دیتای بایت عکس و پرامپت متنی کاربر
428
+ generated_image = await hf_client.image_to_image(
429
+ image_bytes,
430
+ prompt=prompt,
431
+ model="black-forest-labs/FLUX.2-dev"
432
+ )
433
+ break
434
+ except Exception as e:
435
+ last_error_log = str(e)
436
+ continue
437
+
438
+ try:
439
+ if proc_msg:
440
+ msg_id = getattr(proc_msg, 'message_id', None)
441
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
442
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
443
+ except Exception: pass
444
+
445
+ if not generated_image:
446
+ await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
447
+ return
448
+
449
+ try:
450
+ file_name = f"edited_flux_{random.randint(1000, 999999)}.jpg"
451
+ rgb_im = generated_image.convert('RGB')
452
+ rgb_im.save(file_name, format="JPEG", quality=100)
453
+ await asyncio.sleep(1)
454
+ caption_text = f"🪄 ویرایش عکس با هوش مصنوعی Flux.2 انجام شد!\n\n✨ تغییرات خواسته شده: {prompt}"
455
+ upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
456
+ if upload_result is not True:
457
+ await send_with_keyboard(client, chat_id, f"❌ عکس ساخته شد اما خطا در ارسال به روبیکا رخ داد:\n`{str(upload_result)[:800]}`", True)
458
+ if os.path.exists(file_name): os.remove(file_name)
459
+ except Exception as e:
460
+ await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
461
+
462
+
463
+ # --- ۳. پردازش ساخت صدا ---
464
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
465
  try:
466
  proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
 
501
  else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
502
  except Exception: traceback.print_exc()
503
 
504
+ # --- ۳.۵. پردازش پادکست ---
505
  async def process_podcast(client, chat_id, prompt):
506
+ proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست توسط هوش مصنوعی...\n(لطفاً صبور باشید)", False)
507
  available_speakers = []
508
  for num_key, (spk_name, spk_id) in SPEAKERS.items():
509
  gender = "male" if "مرد" in spk_name else "female"
 
515
  async with aiohttp.ClientSession() as session:
516
  try:
517
  async with session.post(url_create, json=payload_create, timeout=60) as resp:
518
+ if resp.status != 202: return await send_with_keyboard(client, chat_id, f"❌ خطا در سرور پادکست: وضعیت {resp.status}", True)
519
  task_id = (await resp.json()).get("task_id")
520
+ except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور پادکست:\n{str(e)}", True)
521
 
522
  url_status = f"https://ezmarynoori-podgen.hf.space/api/podcast-status/{task_id}"
523
  script_data = None
 
531
  script_data = status_data.get("data", {}).get("script", [])
532
  break
533
  elif status_data.get("status") == "failed":
534
+ return await send_with_keyboard(client, chat_id, "❌ متأسفانه هوش مصنوعی نتوانست برای این موضوع سناریو بنویسد.", True)
535
  except Exception: pass
536
 
537
+ if not script_data: return await send_with_keyboard(client, chat_id, "❌ زمان انتظار برای نوشتن سناریو به پایان رسید.", True)
538
 
539
  try:
540
  if proc_msg:
 
543
  if msg_id: await client.delete_messages(chat_id, [msg_id])
544
  except: pass
545
 
546
+ proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال ریکورد و میکس دیالوگ‌های گویندگان (شامل {len(script_data)} نوبت صحبت)...\nاین مرحله زمان‌بر است...", False)
547
 
548
  combined_audio = AudioSegment.empty()
549
  url_generate = "https://ezmarynoori-podgen.hf.space/api/generate"
 
559
  break
560
  except Exception: await asyncio.sleep(2)
561
 
562
+ if not chunk_audio_bytes: return await send_with_keyboard(client, chat_id, f"❌ خطا در تولید صدای بخش {index+1} از سرور. عملیات متوقف شد.", True)
563
 
564
  try:
565
  audio_segment = AudioSegment.from_file(io.BytesIO(chunk_audio_bytes))
566
  combined_audio += audio_segment
567
+ except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا (آیا pydub و ffmpeg نصب است؟):\n{str(e)}", True)
568
 
569
  file_name = f"final_podcast_{random.randint(1000, 999999)}.mp3"
570
  combined_audio.export(file_name, format="mp3")
 
576
  if msg_id: await client.delete_messages(chat_id, [msg_id])
577
  except: pass
578
 
579
+ caption = f"🎧 پادکست شما با موفقیت میکس و ساخته شد!\n\n💡 موضوع شما: {prompt}"
580
  upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", caption)
581
+ if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ پادکست با موفقیت ساخته شد اما روبیکا خطای آپلود داد.\n\n`{str(upload_result)[:800]}`", True)
582
  if os.path.exists(file_name): os.remove(file_name)
583
 
584
+ # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
585
  async def process_stt(client, chat_id, audio_bytes, file_name):
586
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
587
+ proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن...", False)
588
  base64_data = base64.b64encode(audio_bytes).decode('utf-8')
589
  mime_type, _ = mimetypes.guess_type(file_name)
590
  if not mime_type: mime_type = "audio/ogg"
 
592
  keys_to_try = GEMINI_KEYS.copy()
593
  random.shuffle(keys_to_try)
594
  transcribed_text = None
595
+ prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
596
 
597
  async with aiohttp.ClientSession() as session:
598
  for key in keys_to_try:
 
613
  if msg_id: await client.delete_messages(chat_id, [msg_id])
614
  except Exception: pass
615
 
616
+ if transcribed_text: await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
617
+ else: await send_with_keyboard(client, chat_id, f"❌ تبدیل فایل به متن ناموفق بود.", True)
618
 
619
+ # --- ۵. پردازش تحلیل فایل مستقل ---
620
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
621
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False)
622
  proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
623
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
624
  mime_type, _ = mimetypes.guess_type(file_name)
 
647
  if msg_id: await client.delete_messages(chat_id, [msg_id])
648
  except Exception: pass
649
 
650
+ if final_answer: await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
651
  else: await send_with_keyboard(client, chat_id, "❌ پاسخی دریافت نشد.", True)
652
 
653
 
 
722
 
723
  if user_text_str in ["/start", "سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
724
  user_states[chat_id] = {"mode": None, "text": "", "history": [], "file_bytes": None, "file_name": None}
725
+ await send_with_keyboard(client, chat_id, "سلام! به ربات هوشمند آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
726
  return
727
 
728
+ # --- حساب کاربری ---
729
  if user_text_str in ["/account", "حساب کاربری 👤"]:
730
  account_profile = f"""👤 **اطلاعات حساب کاربری شما**
731
 
 
745
 
746
  if user_text_str in ["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
747
  user_states[chat_id] = {"mode": "chat", "text": "", "history": []}
748
+ await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n\nهر سوالی دارید بفرستید تا جواب بدم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
749
  return
750
 
751
  if user_text_str in ["/image", "🎨 عکس", "ساخت تصاویر🎨"]:
752
  user_states[chat_id] = {"mode": "image_waiting_for_text", "text": "", "history": []}
753
+ await send_with_keyboard(client, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\nمتن خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
754
  return
755
 
756
  if user_text_str in ["/edit_image", "ویرایش تصاویر 🪄"]:
757
  user_states[chat_id] = {"mode": "image_edit_waiting_for_image", "text": "", "history": [], "file_bytes": None, "file_name": None}
758
+ await send_with_keyboard(client, chat_id, "🪄 به بخش **ویرایش عکس (Flux.2)** خوش آمدید.\n\nلطفاً ابتدا عکسی که می‌خواهید ویرایش کنید را بفرستید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
759
  return
760
 
761
  if user_text_str in ["/tts", "🎙️ صدا", "تبدیل متن به صدا🗣️"]:
762
  user_states[chat_id] = {"mode": "tts_waiting_for_text", "text": "", "history": []}
763
+ await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
764
  return
765
 
766
  if user_text_str in ["/podcast", "📻 پادکست", "ساخت پادکست 🎙️"]:
767
  user_states[chat_id] = {"mode": "podcast_waiting_for_topic", "text": "", "history": []}
768
+ await send_with_keyboard(client, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
769
  return
770
 
771
  if user_text_str in ["/file", "تحلیل فایل ��"]:
772
  user_states[chat_id] = {"mode": "file_waiting_for_file", "text": "", "history": [], "file_bytes": None, "file_name": None}
773
+ await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً فایل خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
774
  return
775
 
776
  if user_text_str in ["/stt", "فایل صوتی به متن 📝"]:
777
  user_states[chat_id] = {"mode": "stt_waiting_for_audio", "text": "", "history": []}
778
+ await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
779
  return
780
 
781
  current_mode = user_states[chat_id].get("mode")
782
 
783
  if current_mode is None:
784
  if is_file: pass
785
+ elif user_text_str: await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
786
  return
787
 
788
  elif current_mode == "chat":
 
791
  try:
792
  file_bytes = await helper_download_file(client, msg_obj)
793
  asyncio.create_task(process_gemini(client, chat_id, user_text_str, file_bytes=file_bytes, file_name=file_name))
794
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
795
  elif user_text_str: asyncio.create_task(process_gemini(client, chat_id, user_text_str))
796
  return
797
 
 
807
  user_states[chat_id]["file_bytes"] = file_bytes
808
  user_states[chat_id]["mode"] = "image_edit_waiting_for_prompt"
809
  await send_with_keyboard(client, chat_id, "✅ عکس با موفقیت دریافت شد.\n\nحالا دستور خود را به صورت متنی تایپ کنید.\nمثال: یک کلاه قرمز روی سر این گربه بگذار.", False)
810
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت عکس!\n{str(dl_err)}", False)
811
  return
812
 
813
  elif current_mode == "image_edit_waiting_for_prompt":
 
821
 
822
  elif current_mode == "tts_waiting_for_text":
823
  if user_text_str:
824
+ if len(user_text_str) > 2500: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
825
  user_states[chat_id]["text"] = user_text_str
826
  user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
827
+
828
+ # بازگرداندن متن کامل لیست گویندگان
829
+ speakers_menu = """✅ متن شما ذخیره شد.
830
+ لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
831
+ 1. شهاب | 2. آوا | 3. نوید
832
+ 4. آرمان | 5. مهسا | 6. دانا
833
+ 7. سامان | 8. آرش | 9. شبنم
834
+ 10. سحر | 11. مریم | 12. بهرام
835
+ 13. نیکان| 14. فرناز | 15. سارا
836
+ 16. مانی | 17. آرتین | 18. دلنواز
837
+ 19. روژان | 20. امید | 21. بردیا
838
+ 22. ترانه | 23. نیکو | 24. هستی
839
+ 25. کامیار| 26. کیانوش| 27. پویا
840
+ 28. مهتاب | 29. سام | 30. لیدا"""
841
+ await send_with_keyboard(client, chat_id, speakers_menu, False)
842
  return
843
 
844
  elif current_mode == "tts_waiting_for_speaker":
845
+ # تبدیل اعداد فارسی/عربی احتمالی به انگلیسی
846
+ normalized_text = to_english_digits(user_text_str)
847
+
848
+ if normalized_text.isdigit() and normalized_text in SPEAKERS:
849
+ spk_name, spk_id = SPEAKERS[normalized_text]
850
  txt = user_states[chat_id]["text"]
851
  user_states[chat_id]["mode"] = "tts_waiting_for_text"
852
  asyncio.create_task(process_tts(client, chat_id, txt, spk_id, spk_name))
853
+ else:
854
+ await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
855
  return
856
 
857
  elif current_mode == "podcast_waiting_for_topic":
858
  if user_text_str: asyncio.create_task(process_podcast(client, chat_id, user_text_str))
859
+ else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع پادکست خود را به صورت متنی بفرستید.", False)
860
  return
861
 
862
  elif current_mode == "stt_waiting_for_audio":
863
+ if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً یک فایل ارسال کنید.", False)
864
+ await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
865
  try:
866
  audio_bytes = await helper_download_file(client, msg_obj)
867
  asyncio.create_task(process_stt(client, chat_id, audio_bytes, file_name))
868
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دانلود فایل!\n{str(dl_err)}", False)
869
  return
870
 
871
  elif current_mode == "file_waiting_for_file":
872
+ if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک فایل ارسال کنید.", False)
873
+ await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False)
874
  try:
875
  file_bytes = await helper_download_file(client, msg_obj)
876
  user_states[chat_id]["file_bytes"] = file_bytes
877
  user_states[chat_id]["file_name"] = file_name
878
  user_states[chat_id]["mode"] = "file_waiting_for_prompt"
879
+ await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بگویید **چگونه تحلیل شود؟**", False)
880
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
881
  return
882
 
883
  elif current_mode == "file_waiting_for_prompt":
 
886
  saved_name = user_states[chat_id].get("file_name", "file.jpeg")
887
  user_states[chat_id]["mode"] = "file_waiting_for_file"
888
  asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str))
889
+ else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
890
  return
891
 
892
  except Exception: traceback.print_exc()