Opera8 commited on
Commit
e662497
·
verified ·
1 Parent(s): 85d582a

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +209 -189
main.py CHANGED
@@ -6,19 +6,21 @@ import traceback
6
  import asyncio
7
  import base64
8
  import mimetypes
 
9
  from flask import Flask
10
  from rubpy.bot import BotClient, filters
11
 
12
- # ایمپورت‌های جدید برای هاگینگ فیس و کار با عکس
13
  from huggingface_hub import AsyncInferenceClient
14
  from PIL import Image
 
15
 
16
  # --- تنظیمات وب سرور ---
17
  app = Flask(__name__)
18
 
19
  @app.route('/')
20
  def home():
21
- return "ربات یکپارچه آلفا (نسخه پرو + دانلود فایل ۱۰۰٪ تضمینی + چت چندرسانه‌ای + پرامپت‌نویس هوشمند) روشن است! 🚀"
22
 
23
  def run_flask():
24
  app.run(host="0.0.0.0", port=7860)
@@ -42,6 +44,11 @@ MAIN_KEYPAD_DICT = {
42
  {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا با هوش مصنوعی🎙️"}
43
  ]
44
  },
 
 
 
 
 
45
  {
46
  "buttons":[
47
  {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل با هوش مصنوعی 📁"}
@@ -149,7 +156,6 @@ GEMINI_KEYS =[k.strip() for k in GEMINI_KEYS_STR.split(",") if k.strip()]
149
  HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
150
  HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
151
 
152
- # 🔴 تنظیم کردن توکن ربات به صورت سراسری 🔴
153
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
154
 
155
 
@@ -252,15 +258,11 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
252
  return
253
 
254
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
255
-
256
  history = user_states[chat_id].get("history",[])
257
-
258
  new_parts =[]
259
 
260
- if prompt:
261
- new_parts.append({"text": prompt})
262
- elif file_bytes:
263
- new_parts.append({"text": "لطفاً این فایل را به دقت بررسی کن."})
264
 
265
  if file_bytes and file_name:
266
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
@@ -275,22 +277,14 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
275
  elif file_name.endswith('.wav'): mime_type = "audio/wav"
276
  else: mime_type = "image/jpeg"
277
 
278
- new_parts.append({
279
- "inlineData": {
280
- "mimeType": mime_type,
281
- "data": base64_data
282
- }
283
- })
284
 
285
- if history and history[-1]["role"] == "user":
286
- history[-1]["parts"].extend(new_parts)
287
- else:
288
- history.append({"role": "user", "parts": new_parts})
289
 
290
  if len(history) > 40:
291
  history = history[-40:]
292
- if history[0]["role"] == "model":
293
- history = history[1:]
294
 
295
  keys_to_try = GEMINI_KEYS.copy()
296
  random.shuffle(keys_to_try)
@@ -307,23 +301,18 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
307
  try:
308
  final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
309
  break
310
- except (KeyError, IndexError):
311
- continue
312
- except Exception:
313
- continue
314
 
315
  try:
316
  if proc_msg:
317
  msg_id = getattr(proc_msg, 'message_id', None)
318
- if isinstance(proc_msg, dict):
319
- msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
320
- if msg_id:
321
- await client.delete_messages(chat_id,[msg_id])
322
  except Exception: pass
323
 
324
  if not final_answer:
325
- if history and history[-1]["role"] == "user":
326
- history.pop()
327
  await send_with_keyboard(client, chat_id, "❌ متأسفانه پاسخی دریافت نشد. (شاید سایز فایل بیش از حد مجاز بوده است)", False)
328
  return
329
 
@@ -337,77 +326,63 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
337
 
338
  while len(temp_text) > max_len:
339
  split_idx = temp_text.rfind('\n', 0, max_len)
340
- if split_idx == -1:
341
- split_idx = temp_text.rfind(' ', 0, max_len)
342
- if split_idx == -1: split_idx = max_len
343
  chunks.append(temp_text[:split_idx])
344
  temp_text = temp_text[split_idx:].strip()
345
  if temp_text: chunks.append(temp_text)
346
 
347
  for idx, chunk in enumerate(chunks):
348
- if idx != len(chunks) - 1:
349
- chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇"
350
  try:
351
  await send_with_keyboard(client, chat_id, chunk, False)
352
  await asyncio.sleep(2.5)
353
- except Exception:
354
- await asyncio.sleep(2.5)
355
 
356
  except Exception:
357
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
358
 
359
 
360
- # --- ۲. پردازش ساخت عکس (ارتقا یافته با پرامپت‌نویس هوشمند) ---
361
  async def process_image(client, chat_id, prompt):
362
  if not HF_TOKENS:
363
  await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
364
  return
365
 
366
  proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما توسط جیمینای...\n(تبدیل به پرامپت حرفه‌ای)", False)
367
-
368
- # مرحله اول: ارسال پرامپت به جیمینای برای ترجمه و بهینه‌سازی
369
- enhanced_prompt = prompt # مقدار پیش‌فرض اگر جیمینای خطا داد
370
  if GEMINI_KEYS:
371
  keys_to_try_gemini = GEMINI_KEYS.copy()
372
  random.shuffle(keys_to_try_gemini)
373
-
374
- # پرامپت سیستم برای جیمینای
375
  gemini_sys_prompt = (
376
  "You are an expert AI image generation prompt engineer. "
377
  "Translate the following user input to English, and enhance it with high-quality, "
378
- "highly detailed, 4k resolution, cinematic lighting, and visually striking descriptive keywords "
379
- "suitable for Midjourney or Stable Diffusion. "
380
- "Return ONLY the final English prompt string, with absolutely no extra text or explanations. "
381
- f"User input: {prompt}"
382
  )
383
-
384
  async with aiohttp.ClientSession() as session:
385
  for key in keys_to_try_gemini:
386
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
387
- payload = {"contents": [{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
388
  try:
389
  async with session.post(url, json=payload, timeout=20) as response:
390
  if response.status == 200:
391
  data = await response.json()
392
  enhanced_prompt = data["candidates"][0]["content"]["parts"][0]["text"].strip()
393
  break
394
- except Exception:
395
- continue
396
 
397
- # پاک کردن پیام قبلی و اطلاع به کاربر درباره شروع طراحی
398
  try:
399
  if proc_msg:
400
  msg_id = getattr(proc_msg, 'message_id', None)
401
- if isinstance(proc_msg, dict):
402
- msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
403
- if msg_id:
404
- await client.delete_messages(chat_id,[msg_id])
405
  except Exception: pass
406
 
407
  short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
408
- proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📝 پرامپت حرفه‌ای ساخته شده:\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
409
 
410
- # مرحله دوم: ساخت عکس با پرامپت بهینه‌شده
411
  keys_to_try = HF_TOKENS.copy()
412
  random.shuffle(keys_to_try)
413
  generated_image = None
@@ -416,7 +391,6 @@ async def process_image(client, chat_id, prompt):
416
  for token in keys_to_try:
417
  try:
418
  hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
419
- # اینجا پرامپت بهینه‌شده ارسال می‌شود
420
  generated_image = await hf_client.text_to_image(enhanced_prompt, model="Tongyi-MAI/Z-Image-Turbo")
421
  break
422
  except Exception as e:
@@ -426,10 +400,8 @@ async def process_image(client, chat_id, prompt):
426
  try:
427
  if proc_msg:
428
  msg_id = getattr(proc_msg, 'message_id', None)
429
- if isinstance(proc_msg, dict):
430
- msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
431
- if msg_id:
432
- await client.delete_messages(chat_id,[msg_id])
433
  except Exception: pass
434
 
435
  if not generated_image:
@@ -440,30 +412,22 @@ async def process_image(client, chat_id, prompt):
440
  file_name = f"image_{random.randint(1000, 999999)}.jpg"
441
  rgb_im = generated_image.convert('RGB')
442
  rgb_im.save(file_name, format="JPEG", quality=100)
443
-
444
  await asyncio.sleep(1)
445
- caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n✨ ایده اولیه شما: {prompt}\n(مدل: Z-Image-Turbo)"
446
-
447
  upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
448
-
449
  if upload_result is not True:
450
- err_msg = str(upload_result)[:800]
451
- await send_with_keyboard(client, chat_id, f"❌ تصویر در سرور ساخته شد، اما روبیکا در آپلود آن ارور داد.\n\n🔴 لاگ ارور برنامه‌نویس:\n`{err_msg}`", True)
452
-
453
  if os.path.exists(file_name): os.remove(file_name)
454
-
455
  except Exception as e:
456
- await send_with_keyboard(client, chat_id, f"❌ خطایی در فرآیند ذخیره عکس رخ داد:\n{str(e)[:150]}", True)
457
 
458
 
459
  # --- ۳. پردازش ساخت صدا ---
460
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
461
  try:
462
  proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
463
-
464
  payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
465
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
466
-
467
  audio_bytes = None
468
  last_error = "پاسخی دریافت نشد"
469
  workers = WORKER_URLS.copy()
@@ -478,85 +442,166 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
478
  if 'audio' in content_type or response.content_length > 1000:
479
  audio_bytes = await response.read()
480
  break
481
- else: last_error = "فایل نامعتبر از سرور"
482
  else: last_error = f"ارور ({response.status})"
483
- except asyncio.TimeoutError:
484
- last_error = "پایان زمان انتظار سرور."
485
- continue
486
- except Exception as e:
487
- last_error = f"خطا در ارتباط: {str(e)}"
488
- continue
489
 
490
  try:
491
  if proc_msg:
492
  msg_id = getattr(proc_msg, 'message_id', None)
493
- if isinstance(proc_msg, dict):
494
- msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
495
- if msg_id:
496
- await client.delete_messages(chat_id,[msg_id])
497
  except Exception: pass
498
 
499
  if audio_bytes:
500
- file_name = f"audio_{random.randint(1000, 999999)}.wav"
501
  with open(file_name, "wb") as f: f.write(audio_bytes)
502
-
503
  await asyncio.sleep(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
505
- upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", "✅ پردازش صدای شما انجام شد.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
 
507
- if upload_result is not True:
508
- err_msg = str(upload_result)[:800]
509
- await send_with_keyboard(client, chat_id, f"❌ صدا ساخته شد، اما روبیکا در آپلود آن ارور داد.\n\n🔴 لاگ ارور برنامه‌نویس:\n`{err_msg}`", True)
510
 
511
- if os.path.exists(file_name): os.remove(file_name)
512
- else:
513
- await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
514
- except Exception:
515
- traceback.print_exc()
 
 
516
 
 
 
 
 
 
 
 
 
 
 
517
 
518
- # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن (STT) با جیمینای ---
519
- async def process_stt(client, chat_id, audio_bytes, file_name):
520
- if not GEMINI_KEYS:
521
- await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
522
- return
 
 
 
 
523
 
524
- proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن توسط جیمینای... (لطفاً صبور باشید)", False)
525
-
 
 
 
526
  base64_data = base64.b64encode(audio_bytes).decode('utf-8')
527
-
528
  mime_type, _ = mimetypes.guess_type(file_name)
529
- if not mime_type:
530
- if file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg"
531
- elif file_name.endswith('.wav'): mime_type = "audio/wav"
532
- elif file_name.endswith('.mp3'): mime_type = "audio/mp3"
533
- elif file_name.endswith('.mp4'): mime_type = "video/mp4"
534
- else: mime_type = "audio/ogg"
535
 
536
  keys_to_try = GEMINI_KEYS.copy()
537
  random.shuffle(keys_to_try)
538
  transcribed_text = None
539
-
540
- prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده و فقط متن پیاده‌سازی شده را بفرست."
541
 
542
  async with aiohttp.ClientSession() as session:
543
  for key in keys_to_try:
544
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
545
- payload = {
546
- "contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}],
547
- "generationConfig": {"temperature": 0.2, "maxOutputTokens": 8192}
548
- }
549
  try:
550
  async with session.post(url, json=payload, timeout=60) as response:
551
  if response.status == 200:
552
  data = await response.json()
553
- try:
554
- transcribed_text = data["candidates"][0]["content"]["parts"][0]["text"]
555
- break
556
- except (KeyError, IndexError):
557
- continue
558
- except Exception:
559
- continue
560
 
561
  try:
562
  if proc_msg:
@@ -565,31 +610,17 @@ async def process_stt(client, chat_id, audio_bytes, file_name):
565
  if msg_id: await client.delete_messages(chat_id,[msg_id])
566
  except Exception: pass
567
 
568
- if transcribed_text:
569
- await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
570
- else:
571
- await send_with_keyboard(client, chat_id, f"❌ تبدیل فایل به متن ناموفق بود.\n(احتمالاً فرمت فایل پشتیبانی نمی‌شود یا فایل شما صوتی نیست)", True)
572
 
573
 
574
  # --- ۵. پردازش تحلیل فایل مستقل ---
575
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
576
- if not GEMINI_KEYS:
577
- await send_with_keyboard(client, chat_id, " کلیدهای API جیمینای تنظیم نشده‌اند.", False)
578
- return
579
-
580
- proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل و بررسی فایل با هوش مصنوعی...", False)
581
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
582
-
583
  mime_type, _ = mimetypes.guess_type(file_name)
584
- if not mime_type:
585
- if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg"
586
- elif file_name.endswith('.png'): mime_type = "image/png"
587
- elif file_name.endswith('.pdf'): mime_type = "application/pdf"
588
- elif file_name.endswith('.mp4'): mime_type = "video/mp4"
589
- elif file_name.endswith('.mp3'): mime_type = "audio/mp3"
590
- elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg"
591
- elif file_name.endswith('.wav'): mime_type = "audio/wav"
592
- else: mime_type = "image/jpeg"
593
 
594
  keys_to_try = GEMINI_KEYS.copy()
595
  random.shuffle(keys_to_try)
@@ -598,18 +629,13 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
598
  async with aiohttp.ClientSession() as session:
599
  for key in keys_to_try:
600
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
601
- payload = {
602
- "contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}],
603
- "generationConfig": {"temperature": 0.6, "maxOutputTokens": 8192}
604
- }
605
  try:
606
  async with session.post(url, json=payload, timeout=45) as response:
607
  if response.status == 200:
608
  data = await response.json()
609
- try:
610
- final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
611
- break
612
- except (KeyError, IndexError): continue
613
  except Exception: continue
614
 
615
  try:
@@ -619,10 +645,8 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
619
  if msg_id: await client.delete_messages(chat_id,[msg_id])
620
  except Exception: pass
621
 
622
- if final_answer:
623
- await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
624
- else:
625
- await send_with_keyboard(client, chat_id, "❌ در حال حاضر پاسخی برای این فایل دریافت نشد (شاید فرمت فایل پشتیبانی نمی‌شود).", True)
626
 
627
 
628
  # --- تنظیمات ربات روبیکا ---
@@ -672,27 +696,33 @@ else:
672
 
673
  if user_text_str in["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
674
  user_states[chat_id] = {"mode": "chat", "text": "", "history":[]}
675
- await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n(حالا ربات سابقه گفتگو را به یاد می‌آورد)\n\nهر سوالی دارید بفرستید تا جواب بدم:\n💡 نکته: در همین بخش هم می‌توانید برای من عکس یا فایل ارسال کنید تا آن را بررسی کنم.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
676
  return
677
 
678
  if user_text_str in["/image", "🎨 عکس", "ساخت تصاویر با هوش مصنوعی🎨"]:
679
  user_states[chat_id] = {"mode": "image_waiting_for_text", "text": "", "history":[]}
680
- await send_with_keyboard(client, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\n💡 نکته: کافیست تصویر مورد نظرتان را به سادگی توصیف کنید، من خودم آن را به یک پرامپت انگلیسی و حرفه‌ای تبدیل می‌کنم و می‌سازم!\n\nمتن خود را ارسال کنید:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
681
  return
682
 
683
  if user_text_str in["/tts", "🎙️ صدا", "تبدیل متن به صدا با هوش مصنوعی🎙️"]:
684
  user_states[chat_id] = {"mode": "tts_waiting_for_text", "text": "", "history":[]}
685
- await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید (حداکثر 2500 کاراکتر):\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
 
 
 
 
 
 
686
  return
687
 
688
  if user_text_str in["/file", "تحلیل فایل با هوش مصنوعی 📁"]:
689
  user_states[chat_id] = {"mode": "file_waiting_for_file", "text": "", "history":[], "file_bytes": None, "file_name": None}
690
- await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً هر نوع فایلی (عکس، ویدیو، PDF، داکیومنت و...) را که می‌خواهید بررسی شود ارسال کنید:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
691
  return
692
 
693
  if user_text_str in["/stt", "تبدیل فایل صوتی به متن 📝"]:
694
  user_states[chat_id] = {"mode": "stt_waiting_for_audio", "text": "", "history":[]}
695
- await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را فوروارد یا ارسال کنید:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
696
  return
697
 
698
  current_mode = user_states[chat_id].get("mode")
@@ -705,15 +735,12 @@ else:
705
  # --- مسیریابی ---
706
  elif current_mode == "chat":
707
  if is_file:
708
- await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل برای چت هوشمند...", False)
709
  try:
710
  file_bytes = await helper_download_file(client, msg_obj)
711
  asyncio.create_task(process_gemini(client, chat_id, user_text_str, file_bytes=file_bytes, file_name=file_name))
712
- except Exception as dl_err:
713
- err_trace = traceback.format_exc()
714
- await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n\n🔴 لاگ برنامه‌نویس:\n`{err_trace[-300:]}`\n{str(dl_err)}", False)
715
- elif user_text_str:
716
- asyncio.create_task(process_gemini(client, chat_id, user_text_str))
717
  return
718
 
719
  elif current_mode == "image_waiting_for_text":
@@ -723,12 +750,10 @@ else:
723
  elif current_mode == "tts_waiting_for_text":
724
  if user_text_str:
725
  if len(user_text_str) > 2500:
726
- await send_with_keyboard(client, chat_id, "⚠️ متن طولانی است. لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
727
  return
728
-
729
  user_states[chat_id]["text"] = user_text_str
730
  user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
731
-
732
  speakers_menu = """✅ متن شما ذخیره شد.
733
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
734
  1. شهاب | 2. آوا | 3. نوید
@@ -755,36 +780,33 @@ else:
755
  await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
756
  return
757
 
 
 
 
 
 
 
 
 
758
  elif current_mode == "stt_waiting_for_audio":
759
- if not is_file:
760
- await send_with_keyboard(client, chat_id, "⚠️ لطفاً یک فایل (ویس، آهنگ، ویدیو و...) ارسال کنید.", False)
761
- return
762
-
763
  await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
764
  try:
765
  audio_bytes = await helper_download_file(client, msg_obj)
766
- user_states[chat_id]["mode"] = "stt_waiting_for_audio"
767
  asyncio.create_task(process_stt(client, chat_id, audio_bytes, file_name))
768
- except Exception as dl_err:
769
- err_trace = traceback.format_exc()
770
- await send_with_keyboard(client, chat_id, f"❌ خطا در دانلود فایل!\n\n🔴 لاگ برنامه‌نویس:\n`{err_trace[-300:]}`\n{str(dl_err)}", False)
771
  return
772
 
773
  elif current_mode == "file_waiting_for_file":
774
- if not is_file:
775
- await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک فایل (تصویر، ویدیو، PDF و...) ارسال کنید.", False)
776
- return
777
-
778
  await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False)
779
  try:
780
  file_bytes = await helper_download_file(client, msg_obj)
781
  user_states[chat_id]["file_bytes"] = file_bytes
782
  user_states[chat_id]["file_name"] = file_name
783
  user_states[chat_id]["mode"] = "file_waiting_for_prompt"
784
- await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً به صورت متنی بگویید **چگونه تحلیل شود؟**", False)
785
- except Exception as dl_err:
786
- err_trace = traceback.format_exc()
787
- await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n\n🔴 لاگ برنامه‌نویس:\n`{err_trace[-300:]}`\n{str(dl_err)}", False)
788
  return
789
 
790
  elif current_mode == "file_waiting_for_prompt":
@@ -795,12 +817,10 @@ else:
795
  user_states[chat_id]["file_bytes"] = None
796
  user_states[chat_id]["file_name"] = None
797
  asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str))
798
- else:
799
- await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را به صورت متنی بنویسید.", False)
800
  return
801
 
802
- except Exception:
803
- traceback.print_exc()
804
 
805
  if __name__ == "__main__":
806
  threading.Thread(target=run_flask, daemon=True).start()
 
6
  import asyncio
7
  import base64
8
  import mimetypes
9
+ import io
10
  from flask import Flask
11
  from rubpy.bot import BotClient, filters
12
 
13
+ # ایمپورت‌های جدید برای هوش مصنوعی و کار با فایل صوتی
14
  from huggingface_hub import AsyncInferenceClient
15
  from PIL import Image
16
+ from pydub import AudioSegment # ایمپورت اضافه شده برای ترکیب پادکست
17
 
18
  # --- تنظیمات وب سرور ---
19
  app = Flask(__name__)
20
 
21
  @app.route('/')
22
  def home():
23
+ return "ربات یکپارچه آلفا (نسخه پرو + دانلود فایل ۱۰۰٪ تضمینی + چت چندرسانه‌ای + پرامپت‌نویس هوشمند + ساخت پادکست) روشن است! 🚀"
24
 
25
  def run_flask():
26
  app.run(host="0.0.0.0", port=7860)
 
44
  {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا با هوش مصنوعی🎙️"}
45
  ]
46
  },
47
+ {
48
+ "buttons":[
49
+ {"id": "podcast_btn", "type": "Simple", "button_text": "ساخت پادکست با هوش مصنوعی 📻"}
50
+ ]
51
+ },
52
  {
53
  "buttons":[
54
  {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل با هوش مصنوعی 📁"}
 
156
  HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
157
  HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
158
 
 
159
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
160
 
161
 
 
258
  return
259
 
260
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
 
261
  history = user_states[chat_id].get("history",[])
 
262
  new_parts =[]
263
 
264
+ if prompt: new_parts.append({"text": prompt})
265
+ elif file_bytes: new_parts.append({"text": "لطفاً این فایل را به دقت بررسی کن."})
 
 
266
 
267
  if file_bytes and file_name:
268
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
 
277
  elif file_name.endswith('.wav'): mime_type = "audio/wav"
278
  else: mime_type = "image/jpeg"
279
 
280
+ new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
 
 
 
 
 
281
 
282
+ if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
283
+ else: history.append({"role": "user", "parts": new_parts})
 
 
284
 
285
  if len(history) > 40:
286
  history = history[-40:]
287
+ if history[0]["role"] == "model": history = history[1:]
 
288
 
289
  keys_to_try = GEMINI_KEYS.copy()
290
  random.shuffle(keys_to_try)
 
301
  try:
302
  final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
303
  break
304
+ except (KeyError, IndexError): continue
305
+ except Exception: continue
 
 
306
 
307
  try:
308
  if proc_msg:
309
  msg_id = getattr(proc_msg, 'message_id', None)
310
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
311
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
 
 
312
  except Exception: pass
313
 
314
  if not final_answer:
315
+ if history and history[-1]["role"] == "user": history.pop()
 
316
  await send_with_keyboard(client, chat_id, "❌ متأسفانه پاسخی دریافت نشد. (شاید سایز فایل بیش از حد مجاز بوده است)", False)
317
  return
318
 
 
326
 
327
  while len(temp_text) > max_len:
328
  split_idx = temp_text.rfind('\n', 0, max_len)
329
+ if split_idx == -1: split_idx = temp_text.rfind(' ', 0, max_len)
330
+ if split_idx == -1: split_idx = max_len
 
331
  chunks.append(temp_text[:split_idx])
332
  temp_text = temp_text[split_idx:].strip()
333
  if temp_text: chunks.append(temp_text)
334
 
335
  for idx, chunk in enumerate(chunks):
336
+ if idx != len(chunks) - 1: chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇"
 
337
  try:
338
  await send_with_keyboard(client, chat_id, chunk, False)
339
  await asyncio.sleep(2.5)
340
+ except Exception: await asyncio.sleep(2.5)
 
341
 
342
  except Exception:
343
  await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
344
 
345
 
346
+ # --- ۲. پردازش ساخت عکس ---
347
  async def process_image(client, chat_id, prompt):
348
  if not HF_TOKENS:
349
  await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
350
  return
351
 
352
  proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما توسط جیمینای...\n(تبدیل به پرامپت حرفه‌ای)", False)
353
+ enhanced_prompt = prompt
 
 
354
  if GEMINI_KEYS:
355
  keys_to_try_gemini = GEMINI_KEYS.copy()
356
  random.shuffle(keys_to_try_gemini)
 
 
357
  gemini_sys_prompt = (
358
  "You are an expert AI image generation prompt engineer. "
359
  "Translate the following user input to English, and enhance it with high-quality, "
360
+ "highly detailed, 4k resolution, cinematic lighting, and visually striking descriptive keywords. "
361
+ "Return ONLY the final English prompt string."
362
+ f"\nUser input: {prompt}"
 
363
  )
 
364
  async with aiohttp.ClientSession() as session:
365
  for key in keys_to_try_gemini:
366
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
367
+ payload = {"contents":[{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
368
  try:
369
  async with session.post(url, json=payload, timeout=20) as response:
370
  if response.status == 200:
371
  data = await response.json()
372
  enhanced_prompt = data["candidates"][0]["content"]["parts"][0]["text"].strip()
373
  break
374
+ except Exception: continue
 
375
 
 
376
  try:
377
  if proc_msg:
378
  msg_id = getattr(proc_msg, 'message_id', None)
379
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
380
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
 
 
381
  except Exception: pass
382
 
383
  short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
384
+ proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📝 پرامپت ساخته شده:\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
385
 
 
386
  keys_to_try = HF_TOKENS.copy()
387
  random.shuffle(keys_to_try)
388
  generated_image = None
 
391
  for token in keys_to_try:
392
  try:
393
  hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
 
394
  generated_image = await hf_client.text_to_image(enhanced_prompt, model="Tongyi-MAI/Z-Image-Turbo")
395
  break
396
  except Exception as e:
 
400
  try:
401
  if proc_msg:
402
  msg_id = getattr(proc_msg, 'message_id', None)
403
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
404
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
 
 
405
  except Exception: pass
406
 
407
  if not generated_image:
 
412
  file_name = f"image_{random.randint(1000, 999999)}.jpg"
413
  rgb_im = generated_image.convert('RGB')
414
  rgb_im.save(file_name, format="JPEG", quality=100)
 
415
  await asyncio.sleep(1)
416
+ caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n✨ ایده اولیه: {prompt}"
 
417
  upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
 
418
  if upload_result is not True:
419
+ await send_with_keyboard(client, chat_id, f"❌ خطا در آپلود روبیکا:\n`{str(upload_result)[:800]}`", True)
 
 
420
  if os.path.exists(file_name): os.remove(file_name)
 
421
  except Exception as e:
422
+ await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
423
 
424
 
425
  # --- ۳. پردازش ساخت صدا ---
426
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
427
  try:
428
  proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
 
429
  payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
430
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
 
431
  audio_bytes = None
432
  last_error = "پاسخی دریافت نشد"
433
  workers = WORKER_URLS.copy()
 
442
  if 'audio' in content_type or response.content_length > 1000:
443
  audio_bytes = await response.read()
444
  break
445
+ else: last_error = "فایل نامعتبر"
446
  else: last_error = f"ارور ({response.status})"
447
+ except Exception as e: last_error = f"خطا: {str(e)}"; continue
 
 
 
 
 
448
 
449
  try:
450
  if proc_msg:
451
  msg_id = getattr(proc_msg, 'message_id', None)
452
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
453
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
 
 
454
  except Exception: pass
455
 
456
  if audio_bytes:
457
+ file_name = f"audio_{random.randint(1000, 999999)}.mp3"
458
  with open(file_name, "wb") as f: f.write(audio_bytes)
 
459
  await asyncio.sleep(1)
460
+ upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", "✅ صدای شما آماده شد.")
461
+ if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ ارور آپلود:\n`{str(upload_result)[:800]}`", True)
462
+ if os.path.exists(file_name): os.remove(file_name)
463
+ else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
464
+ except Exception: traceback.print_exc()
465
+
466
+ # --- بخش جدید: پردازش و ساخت پادکست (اتصال به سرور HF) ---
467
+ async def process_podcast(client, chat_id, prompt):
468
+ proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست توسط هوش مصنوعی...\n(لطفاً صبور باشید)", False)
469
+
470
+ # آماده‌سازی دیتای گویندگان پیش‌فرض (همانند مرورگر)
471
+ available_speakers =[]
472
+ for num_key, (spk_name, spk_id) in SPEAKERS.items():
473
+ gender = "male" if "مرد" in spk_name else "female"
474
+ available_speakers.append({"id": spk_id, "name": spk_name.split(' (')[0], "gender": gender})
475
+
476
+ url_create = "https://ezmarynoori-podgen.hf.space/api/create-full-podcast"
477
+ payload_create = {
478
+ "prompt": prompt,
479
+ "available_speakers": available_speakers
480
+ }
481
+
482
+ async with aiohttp.ClientSession() as session:
483
+ try:
484
+ # 1. درخواست نگارش سناریو به اسپیس ساخت پادکست
485
+ async with session.post(url_create, json=payload_create, timeout=60) as resp:
486
+ if resp.status != 202:
487
+ await send_with_keyboard(client, chat_id, f"❌ خطا در سرور پادکست: وضعیت {resp.status}", True)
488
+ return
489
+ data = await resp.json()
490
+ task_id = data.get("task_id")
491
+ except Exception as e:
492
+ await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور پادکست:\n{str(e)}", True)
493
+ return
494
+
495
+ # 2. بررسی وضعیت (Polling) تا زمان آماده شدن سناریو
496
+ url_status = f"https://ezmarynoori-podgen.hf.space/api/podcast-status/{task_id}"
497
+ script_data = None
498
+ for _ in range(40): # تا 120 ثانیه صبر میکند
499
+ await asyncio.sleep(3)
500
+ try:
501
+ async with session.get(url_status) as resp:
502
+ if resp.status == 200:
503
+ status_data = await resp.json()
504
+ if status_data.get("status") == "completed":
505
+ script_data = status_data.get("data", {}).get("script",[])
506
+ break
507
+ elif status_data.get("status") == "failed":
508
+ await send_with_keyboard(client, chat_id, "❌ متأسفانه هوش مصنوعی نتوانست برای این موضوع سناریو بنویسد.", True)
509
+ return
510
+ except Exception: pass
511
 
512
+ if not script_data:
513
+ await send_with_keyboard(client, chat_id, "❌ زمان انتظار برای نوشتن سناریو به پایان رسید.", True)
514
+ return
515
+
516
+ # آپدیت پیام به کاربر
517
+ try:
518
+ if proc_msg:
519
+ msg_id = getattr(proc_msg, 'message_id', None)
520
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
521
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
522
+ except: pass
523
+
524
+ proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال ریکورد و میکس دیالوگ‌های گویندگان (شامل {len(script_data)} نوبت صحبت)...\nاین مرحله زمان‌بر است...", False)
525
+
526
+ # 3. دریافت فایل صوتی هر دیالوگ و میکس آن‌ها
527
+ combined_audio = AudioSegment.empty()
528
+ url_generate = "https://ezmarynoori-podgen.hf.space/api/generate"
529
+
530
+ for index, turn in enumerate(script_data):
531
+ payload_gen = {
532
+ "text": turn["dialogue"],
533
+ "speaker": turn["speaker_id"],
534
+ "temperature": 0.9
535
+ }
536
+
537
+ chunk_audio_bytes = None
538
+ for attempt in range(3): # ۳ بار تلاش برای هر بخش
539
+ try:
540
+ async with session.post(url_generate, json=payload_gen, timeout=120) as resp:
541
+ if resp.status == 200:
542
+ chunk_audio_bytes = await resp.read()
543
+ break
544
+ except Exception:
545
+ await asyncio.sleep(2)
546
 
547
+ if not chunk_audio_bytes:
548
+ await send_with_keyboard(client, chat_id, f"❌ خطا در تولید صدای بخش {index+1} از سرور. عملیات متوقف شد.", True)
549
+ return
550
 
551
+ try:
552
+ # تبدیل بایت به AudioSegment با استفاده از pydub
553
+ audio_segment = AudioSegment.from_file(io.BytesIO(chunk_audio_bytes))
554
+ combined_audio += audio_segment
555
+ except Exception as e:
556
+ await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا (آیا pydub و ffmpeg نصب است؟):\n{str(e)}", True)
557
+ return
558
 
559
+ # 4. خروجی گرفتن و ارسال به کاربر
560
+ file_name = f"final_podcast_{random.randint(1000, 999999)}.mp3"
561
+ combined_audio.export(file_name, format="mp3")
562
+
563
+ try:
564
+ if proc_msg:
565
+ msg_id = getattr(proc_msg, 'message_id', None)
566
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
567
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
568
+ except: pass
569
 
570
+ caption = f"🎧 پادکست شما با موفقیت میکس و ساخته شد!\n\n💡 موضوع شما: {prompt}"
571
+ upload_result = await helper_upload_file(client, chat_id, file_name, "Voice", caption)
572
+
573
+ if upload_result is not True:
574
+ err_msg = str(upload_result)[:800]
575
+ await send_with_keyboard(client, chat_id, f"❌ پادکست با موفقیت در سرور ساخته شد اما روبیکا خطای آپلود داد.\n\n`{err_msg}`", True)
576
+
577
+ if os.path.exists(file_name):
578
+ os.remove(file_name)
579
 
580
+
581
+ # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
582
+ async def process_stt(client, chat_id, audio_bytes, file_name):
583
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
584
+ proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن...", False)
585
  base64_data = base64.b64encode(audio_bytes).decode('utf-8')
 
586
  mime_type, _ = mimetypes.guess_type(file_name)
587
+ if not mime_type: mime_type = "audio/ogg"
 
 
 
 
 
588
 
589
  keys_to_try = GEMINI_KEYS.copy()
590
  random.shuffle(keys_to_try)
591
  transcribed_text = None
592
+ prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
 
593
 
594
  async with aiohttp.ClientSession() as session:
595
  for key in keys_to_try:
596
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
597
+ payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.2}}
 
 
 
598
  try:
599
  async with session.post(url, json=payload, timeout=60) as response:
600
  if response.status == 200:
601
  data = await response.json()
602
+ transcribed_text = data["candidates"][0]["content"]["parts"][0]["text"]
603
+ break
604
+ except Exception: continue
 
 
 
 
605
 
606
  try:
607
  if proc_msg:
 
610
  if msg_id: await client.delete_messages(chat_id,[msg_id])
611
  except Exception: pass
612
 
613
+ if transcribed_text: await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
614
+ else: await send_with_keyboard(client, chat_id, f" تبدیل فایل به متن ناموفق بود.", True)
 
 
615
 
616
 
617
  # --- ۵. پردازش تحلیل فایل مستقل ---
618
  async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
619
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False)
620
+ proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
 
 
 
621
  base64_data = base64.b64encode(file_bytes).decode('utf-8')
 
622
  mime_type, _ = mimetypes.guess_type(file_name)
623
+ if not mime_type: mime_type = "image/jpeg"
 
 
 
 
 
 
 
 
624
 
625
  keys_to_try = GEMINI_KEYS.copy()
626
  random.shuffle(keys_to_try)
 
629
  async with aiohttp.ClientSession() as session:
630
  for key in keys_to_try:
631
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
632
+ payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.6}}
 
 
 
633
  try:
634
  async with session.post(url, json=payload, timeout=45) as response:
635
  if response.status == 200:
636
  data = await response.json()
637
+ final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
638
+ break
 
 
639
  except Exception: continue
640
 
641
  try:
 
645
  if msg_id: await client.delete_messages(chat_id,[msg_id])
646
  except Exception: pass
647
 
648
+ if final_answer: await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
649
+ else: await send_with_keyboard(client, chat_id, " پاسخی دریافت نشد.", True)
 
 
650
 
651
 
652
  # --- تنظیمات ربات روبیکا ---
 
696
 
697
  if user_text_str in["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
698
  user_states[chat_id] = {"mode": "chat", "text": "", "history":[]}
699
+ await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n\nهر سوالی دارید بفرستید تا جواب بدم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
700
  return
701
 
702
  if user_text_str in["/image", "🎨 عکس", "ساخت تصاویر با هوش مصنوعی🎨"]:
703
  user_states[chat_id] = {"mode": "image_waiting_for_text", "text": "", "history":[]}
704
+ await send_with_keyboard(client, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\nمتن خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
705
  return
706
 
707
  if user_text_str in["/tts", "🎙️ صدا", "تبدیل متن به صدا با هوش مصنوعی🎙️"]:
708
  user_states[chat_id] = {"mode": "tts_waiting_for_text", "text": "", "history":[]}
709
+ await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
710
+ return
711
+
712
+ # --- دکمه جدید برای پادکست ---
713
+ if user_text_str in["/podcast", "📻 پادکست", "ساخت پادکست با هوش مصنوعی 📻"]:
714
+ user_states[chat_id] = {"mode": "podcast_waiting_for_topic", "text": "", "history":[]}
715
+ await send_with_keyboard(client, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
716
  return
717
 
718
  if user_text_str in["/file", "تحلیل فایل با هوش مصنوعی 📁"]:
719
  user_states[chat_id] = {"mode": "file_waiting_for_file", "text": "", "history":[], "file_bytes": None, "file_name": None}
720
+ await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً فایل خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
721
  return
722
 
723
  if user_text_str in["/stt", "تبدیل فایل صوتی به متن 📝"]:
724
  user_states[chat_id] = {"mode": "stt_waiting_for_audio", "text": "", "history":[]}
725
+ await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
726
  return
727
 
728
  current_mode = user_states[chat_id].get("mode")
 
735
  # --- مسیریابی ---
736
  elif current_mode == "chat":
737
  if is_file:
738
+ await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
739
  try:
740
  file_bytes = await helper_download_file(client, msg_obj)
741
  asyncio.create_task(process_gemini(client, chat_id, user_text_str, file_bytes=file_bytes, file_name=file_name))
742
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
743
+ elif user_text_str: asyncio.create_task(process_gemini(client, chat_id, user_text_str))
 
 
 
744
  return
745
 
746
  elif current_mode == "image_waiting_for_text":
 
750
  elif current_mode == "tts_waiting_for_text":
751
  if user_text_str:
752
  if len(user_text_str) > 2500:
753
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
754
  return
 
755
  user_states[chat_id]["text"] = user_text_str
756
  user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
 
757
  speakers_menu = """✅ متن شما ذخیره شد.
758
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
759
  1. شهاب | 2. آوا | 3. نوید
 
780
  await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
781
  return
782
 
783
+ # --- بخش مسیریابی برای قابلیت جدید (پادکست) ---
784
+ elif current_mode == "podcast_waiting_for_topic":
785
+ if user_text_str:
786
+ asyncio.create_task(process_podcast(client, chat_id, user_text_str))
787
+ else:
788
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع پادکست خود را به صورت متنی بفرستید.", False)
789
+ return
790
+
791
  elif current_mode == "stt_waiting_for_audio":
792
+ if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً یک فایل ارسال کنید.", False)
 
 
 
793
  await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل...", False)
794
  try:
795
  audio_bytes = await helper_download_file(client, msg_obj)
 
796
  asyncio.create_task(process_stt(client, chat_id, audio_bytes, file_name))
797
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دانلود فایل!\n{str(dl_err)}", False)
 
 
798
  return
799
 
800
  elif current_mode == "file_waiting_for_file":
801
+ if not is_file: return await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک فایل ارسال کنید.", False)
 
 
 
802
  await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False)
803
  try:
804
  file_bytes = await helper_download_file(client, msg_obj)
805
  user_states[chat_id]["file_bytes"] = file_bytes
806
  user_states[chat_id]["file_name"] = file_name
807
  user_states[chat_id]["mode"] = "file_waiting_for_prompt"
808
+ await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بگویید **چگونه تحلیل شود؟**", False)
809
+ except Exception as dl_err: await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
 
 
810
  return
811
 
812
  elif current_mode == "file_waiting_for_prompt":
 
817
  user_states[chat_id]["file_bytes"] = None
818
  user_states[chat_id]["file_name"] = None
819
  asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, saved_name, user_text_str))
820
+ else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
 
821
  return
822
 
823
+ except Exception: traceback.print_exc()
 
824
 
825
  if __name__ == "__main__":
826
  threading.Thread(target=run_flask, daemon=True).start()