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

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +253 -75
main.py CHANGED
@@ -13,7 +13,7 @@ import datetime
13
  import string
14
  import uuid
15
  from flask import Flask
16
- from rubpy import BotClient, filters
17
 
18
  # ایمپورت‌های جدید برای هوش مصنوعی، کار با فایل صوتی و دیتابیس هاگینگ فیس
19
  from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download
@@ -229,6 +229,11 @@ MAIN_KEYPAD_DICT = {
229
  {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل 📁"}
230
  ]
231
  },
 
 
 
 
 
232
  {
233
  "buttons":[
234
  {"id": "account_btn", "type": "Simple", "button_text": "حساب کاربری 👤"},
@@ -430,82 +435,114 @@ HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
430
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
431
 
432
 
433
- # --- 🚨 تابع اختصاصی آپلود فایل به روبیکا (نسخه اصلاح شده) 🚨 ---
434
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
435
  abs_path = os.path.abspath(file_name)
436
  error_logs =[]
437
 
438
  api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in["voice", "Voice", "audio"] else "File"
439
 
440
- try:
441
- url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
442
- url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
443
 
444
- async with aiohttp.ClientSession() as session:
445
- # ۱. درخواست آدرس آپلود از روبیکا
446
- async with session.post(url_request, json={"type": api_file_type}, timeout=20) as resp:
447
- req_data = await resp.json()
448
-
449
- if req_data.get("status") == "OK":
450
- data_dict = req_data.get("data", {})
451
- upload_url = data_dict.get("upload_url")
 
 
 
 
 
 
 
452
 
453
- # اگر آدرس آپلود با موفقیت دریافت شد
454
- if upload_url:
455
- with open(abs_path, "rb") as f:
456
- form = aiohttp.FormData()
457
- form.add_field('file', f, filename=os.path.basename(abs_path))
458
-
459
- # ۲. ارسال (پست کردن) فایل به لینک آپلود
460
- async with session.post(upload_url, data=form, timeout=60) as up_resp:
461
- up_data = await up_resp.json()
462
 
463
- # ۳. گرفتن file_id از پاسخی که سرور آپلود برمی‌گرداند
464
- final_file_id = None
465
- if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
466
- if "data" in up_data:
467
- final_file_id = up_data["data"].get("file_id") or up_data["data"].get("id")
468
- elif "file_id" in up_data:
469
- final_file_id = up_data.get("file_id")
 
 
470
 
471
- if final_file_id:
472
- # ۴. ارسال نهایی پیام (به همراه فایل) به کاربر
473
- send_payload = {
474
- "chat_id": str(chat_id),
475
- "file_id": str(final_file_id),
476
- "text": caption,
477
- "chat_keypad_type": "New",
478
- "chat_keypad": MAIN_KEYPAD_DICT
479
- }
480
- async with session.post(url_send, json=send_payload, timeout=20) as send_resp:
481
- s_data = await send_resp.json()
482
- if s_data.get("status") == "OK":
483
- return True
484
- else:
485
- error_logs.append(f"SendFile API Error: {s_data}")
486
- else:
487
- error_logs.append(f"Upload API Error (No file_id): {up_data}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  else:
489
- error_logs.append(f"Missing upload_url in Response: {data_dict}")
490
- else:
491
- error_logs.append(f"Request API Error: {req_data}")
492
- except Exception as e:
493
- error_logs.append(f"Raw HTTP Error: {e}")
494
 
495
- # در صورت شکست، تلاش از طریق متدهای کتابخانه rubpy (Fallback)
496
  try:
497
  if hasattr(client, "send_file"):
498
  await client.send_file(chat_id, abs_path)
499
  if caption:
500
  await send_with_keyboard(client, chat_id, caption, True)
501
  return True
502
- elif hasattr(client, "send_document"): # استفاده از متدهای مدرن‌تر در آپدیت‌های جدید rubpy
503
  await client.send_document(chat_id, abs_path, caption=caption)
504
  return True
505
  except Exception as e:
506
- error_logs.append(f"Rubpy Send Error: {e}")
507
 
508
- return "\n".join(error_logs)
509
 
510
 
511
  WORKER_URLS =[
@@ -906,20 +943,20 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
906
  user_credits_db[str_chat_id]["tts"] -= 1
907
  save_db(user_credits_db)
908
 
909
- file_name = f"audio_{uuid.uuid4().hex}.mp3"
910
- with open(file_name, "wb") as f: f.write(audio_bytes)
911
- await asyncio.sleep(1)
912
 
913
- # ارسال به صورت ویس
914
- upload_result_voice = await helper_upload_file(client, chat_id, file_name, "Voice", "✅ صدای شما (به صورت ویس) آماده شد.")
915
 
916
- # ارسال به صورت فایل MP3
917
- upload_result_file = await helper_upload_file(client, chat_id, file_name, "File", "✅ فایل MP3 صدای شما:")
 
 
918
 
919
- if upload_result_voice is not True and upload_result_file is not True:
920
- await send_with_keyboard(client, chat_id, f"❌ ارور آپلود:\n`{str(upload_result_voice)[:800]}`", True)
921
 
922
- if os.path.exists(file_name): os.remove(file_name)
923
  else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
924
  except Exception: traceback.print_exc()
925
 
@@ -968,7 +1005,7 @@ async def process_podcast(client, chat_id, prompt):
968
  if proc_msg:
969
  msg_id = getattr(proc_msg, 'message_id', None)
970
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
971
- if msg_id: await client.delete_messages(chat_id, [msg_id])
972
  except: pass
973
 
974
  proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال ریکورد و میکس دیالوگ‌های گویندگان (شامل {len(script_data)} نوبت صحبت)...\nاین مرحله زمان‌بر است...", False)
@@ -999,8 +1036,9 @@ async def process_podcast(client, chat_id, prompt):
999
  user_credits_db[str_chat_id]["podcast"] -= 1
1000
  save_db(user_credits_db)
1001
 
1002
- file_name = f"final_podcast_{uuid.uuid4().hex}.mp3"
1003
- combined_audio.export(file_name, format="mp3")
 
1004
 
1005
  try:
1006
  if proc_msg:
@@ -1009,16 +1047,15 @@ async def process_podcast(client, chat_id, prompt):
1009
  if msg_id: await client.delete_messages(chat_id,[msg_id])
1010
  except: pass
1011
 
1012
- caption_voice = f"🎧 پادکست شما با موفقیت میکس و ساخته شد! (ویس)\n\n💡 موضوع شما: {prompt}"
1013
  caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
1014
 
1015
- upload_result_voice = await helper_upload_file(client, chat_id, file_name, "Voice", caption_voice)
1016
- upload_result_file = await helper_upload_file(client, chat_id, file_name, "File", caption_file)
1017
 
1018
- if upload_result_voice is not True and upload_result_file is not True:
1019
- await send_with_keyboard(client, chat_id, f"❌ پادکست ساخته شد اما روبیکا خطای آپلود داد.\n\n`{str(upload_result_voice)[:800]}`", True)
1020
 
1021
- if os.path.exists(file_name): os.remove(file_name)
1022
 
1023
 
1024
  # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
@@ -1116,13 +1153,142 @@ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1116
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1117
 
1118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1119
  # --- تنظیمات ربات روبیکا ---
1120
  if not bot_token:
1121
  print("خطا: توکن ربات روبیکا وارد نشده است!")
1122
  else:
1123
  bot = BotClient(bot_token)
1124
 
1125
- @bot.on_update()
1126
  async def main_handler(client, update):
1127
  global BOT_GUID
1128
 
@@ -1476,6 +1642,11 @@ else:
1476
  await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1477
  return
1478
 
 
 
 
 
 
1479
  current_mode = user_states[chat_id].get("mode")
1480
 
1481
  if current_mode is None:
@@ -1585,6 +1756,13 @@ else:
1585
  else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1586
  return
1587
 
 
 
 
 
 
 
 
1588
  except Exception: traceback.print_exc()
1589
 
1590
  if __name__ == "__main__":
 
13
  import string
14
  import uuid
15
  from flask import Flask
16
+ from rubpy.bot import BotClient, filters
17
 
18
  # ایمپورت‌های جدید برای هوش مصنوعی، کار با فایل صوتی و دیتابیس هاگینگ فیس
19
  from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download
 
229
  {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل 📁"}
230
  ]
231
  },
232
+ {
233
+ "buttons":[
234
+ {"id": "create_file_btn", "type": "Simple", "button_text": "ساخت فایل 📄"}
235
+ ]
236
+ },
237
  {
238
  "buttons":[
239
  {"id": "account_btn", "type": "Simple", "button_text": "حساب کاربری 👤"},
 
435
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
436
 
437
 
438
+ # --- 🚨 تابع اختصاصی آپلود فایل به روبیکا (مجهز به سیستم Fallback هوشمند صوتی و Music) 🚨 ---
439
  async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
440
  abs_path = os.path.abspath(file_name)
441
  error_logs =[]
442
 
443
  api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in["voice", "Voice", "audio"] else "File"
444
 
445
+ # اگر قرار است ویس ارسال شود اما فایل پسوند مناسب ندارد، برای جلوگیری از ارور فوراً به Music تبدیل می‌کنیم
446
+ if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
447
+ api_file_type = "Music"
448
 
449
+ # سیستم ۳ بار تلاش مجدد برای جلوگیری از قطعی سرور روبیکا
450
+ for attempt in range(3):
451
+ try:
452
+ url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
453
+ url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
454
+
455
+ async with aiohttp.ClientSession() as session:
456
+ # ۱. درخواست آدرس آپلود از روبیکا
457
+ async with session.post(url_request, json={"type": api_file_type}, timeout=20) as resp:
458
+ if resp.status != 200:
459
+ error_logs.append(f"Request HTTP {resp.status}")
460
+ await asyncio.sleep(1.5)
461
+ continue
462
+
463
+ req_data = await resp.json()
464
 
465
+ if req_data.get("status") == "OK":
466
+ upload_url = req_data.get("data", {}).get("upload_url")
467
+
468
+ # اگر آدرس آپلود با موفقیت دریافت شد
469
+ if upload_url:
470
+ with open(abs_path, "rb") as f:
471
+ form = aiohttp.FormData()
472
+ form.add_field('file', f, filename=os.path.basename(abs_path))
 
473
 
474
+ # ۲. ارسال فایل به لینک آپلود
475
+ async with session.post(upload_url, data=form, timeout=60) as up_resp:
476
+ if up_resp.status != 200:
477
+ error_logs.append(f"Upload HTTP {up_resp.status}")
478
+ # 🔴 اگر ارور 502 داد یعنی روبیکا فرمت ویس را پس زده است، پس تبدیل به حالت Music می‌کنیم
479
+ if up_resp.status == 502 and api_file_type == "Voice":
480
+ api_file_type = "Music"
481
+ await asyncio.sleep(1.5)
482
+ continue
483
 
484
+ try:
485
+ up_data = await up_resp.json()
486
+ except Exception as json_err:
487
+ error_logs.append(f"JSON Decode Error: {json_err}")
488
+ await asyncio.sleep(1.5)
489
+ continue
490
+
491
+ # ۳. گرفتن file_id از پاسخی که سرور آپلود برمی‌گرداند
492
+ final_file_id = None
493
+ if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
494
+ if "data" in up_data and isinstance(up_data["data"], dict):
495
+ final_file_id = up_data["data"].get("file_id") or up_data["data"].get("id")
496
+ elif "file_id" in up_data:
497
+ final_file_id = up_data.get("file_id")
498
+
499
+ if final_file_id:
500
+ # ۴. ارسال نهایی پیام
501
+ send_payload = {
502
+ "chat_id": str(chat_id),
503
+ "file_id": str(final_file_id),
504
+ "text": caption,
505
+ "chat_keypad_type": "New",
506
+ "chat_keypad": MAIN_KEYPAD_DICT
507
+ }
508
+ async with session.post(url_send, json=send_payload, timeout=20) as send_resp:
509
+ if send_resp.status != 200:
510
+ error_logs.append(f"Send HTTP {send_resp.status}")
511
+ await asyncio.sleep(1.5)
512
+ continue
513
+
514
+ s_data = await send_resp.json()
515
+ if s_data.get("status") == "OK":
516
+ return True
517
+ else:
518
+ error_logs.append(f"SendFile API Error: {s_data}")
519
+ else:
520
+ # 🔴 اگر فرمت فایل نامعتبر بود، به جای ویس، به صورت موزیک (دارای دکمه پخش) ارسال کن
521
+ if up_data.get("status") == "INVALID_INPUT" and api_file_type == "Voice":
522
+ api_file_type = "Music"
523
+ error_logs.append(f"Upload API Error: {up_data}")
524
+ else:
525
+ error_logs.append(f"Missing upload_url in Response: {req_data}")
526
  else:
527
+ error_logs.append(f"Request API Error: {req_data}")
528
+ except Exception as e:
529
+ error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
530
+ await asyncio.sleep(1.5)
 
531
 
532
+ # تلاش نهایی از طریق روب‌پای به عنوان راه جایگزین
533
  try:
534
  if hasattr(client, "send_file"):
535
  await client.send_file(chat_id, abs_path)
536
  if caption:
537
  await send_with_keyboard(client, chat_id, caption, True)
538
  return True
539
+ elif hasattr(client, "send_document"):
540
  await client.send_document(chat_id, abs_path, caption=caption)
541
  return True
542
  except Exception as e:
543
+ error_logs.append(f"Rubpy Send Error: {str(e)[:100]}")
544
 
545
+ return "\n".join(error_logs[-4:])
546
 
547
 
548
  WORKER_URLS =[
 
943
  user_credits_db[str_chat_id]["tts"] -= 1
944
  save_db(user_credits_db)
945
 
946
+ # فایل صوتی را فقط به صورت MP3 ذخیره می‌کنیم تا از مشکل 502 روبیکا جلوگیری شود
947
+ file_name_mp3 = f"audio_{uuid.uuid4().hex}.mp3"
 
948
 
949
+ with open(file_name_mp3, "wb") as f: f.write(audio_bytes)
 
950
 
951
+ await asyncio.sleep(1)
952
+
953
+ # ارسال فقط به صورت فایل دانلودشونده MP3 (حالت Voice حذف شد)
954
+ upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
955
 
956
+ if upload_result_file is not True:
957
+ await send_with_keyboard(client, chat_id, f"❌ ارور آپلود فایل:\n`{str(upload_result_file)[:800]}`", True)
958
 
959
+ if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
960
  else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
961
  except Exception: traceback.print_exc()
962
 
 
1005
  if proc_msg:
1006
  msg_id = getattr(proc_msg, 'message_id', None)
1007
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1008
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
1009
  except: pass
1010
 
1011
  proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال ریکورد و میکس دیالوگ‌های گویندگان (شامل {len(script_data)} نوبت صحبت)...\nاین مرحله زمان‌بر است...", False)
 
1036
  user_credits_db[str_chat_id]["podcast"] -= 1
1037
  save_db(user_credits_db)
1038
 
1039
+ # فقط با فرمت MP3 خروجی می‌دهیم (بدون تبدیل OGG)
1040
+ file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
1041
+ combined_audio.export(file_name_mp3, format="mp3")
1042
 
1043
  try:
1044
  if proc_msg:
 
1047
  if msg_id: await client.delete_messages(chat_id,[msg_id])
1048
  except: pass
1049
 
 
1050
  caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
1051
 
1052
+ # ارسال فقط به صورت فایل MP3
1053
+ upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", caption_file)
1054
 
1055
+ if upload_result_file is not True:
1056
+ await send_with_keyboard(client, chat_id, f"❌ پادکست ساخته شد اما روبیکا خطای آپلود داد.\n\n`{str(upload_result_file)[:800]}`", True)
1057
 
1058
+ if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1059
 
1060
 
1061
  # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
 
1153
  await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1154
 
1155
 
1156
+ # --- ۵.۵. پردازش ساخت مقاله و تبدیل به فایل (PDF & DOCX) ---
1157
+ async def process_create_file(client, chat_id, topic):
1158
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1159
+ creds = get_user_credits(str_chat_id)
1160
+
1161
+ # بررسی محدودیت بخش ساخت فایل (کسر از اعتبار پیام چت)
1162
+ if creds["chat"] <= 0:
1163
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1164
+
1165
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
1166
+
1167
+ proc_msg = await send_with_keyboard(client, chat_id, "✍️ در حال تحقیق و نگارش مقاله جامع و حرفه‌ای...\n(این عملیات با توجه به طولانی بودن متن ممکن است کمی طول بکشد)", False)
1168
+
1169
+ ai_prompt = f"یک مقاله بسیار جامع، کاملا حرفه‌ای، بسیار طولانی و با جزئیات کامل درباره موضوع زیر به زبان فارسی بنویس. فقط متن مقاله را بده و هیچ توضیح اضافه‌ای نده:\n\nموضوع: {topic}"
1170
+ article_text = None
1171
+
1172
+ keys_to_try = get_next_gemini_keys(100)
1173
+ async with aiohttp.ClientSession() as session:
1174
+ for key in keys_to_try:
1175
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1176
+ payload = {"contents": [{"parts":[{"text": ai_prompt}]}], "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
1177
+ try:
1178
+ async with session.post(url, json=payload, timeout=60) as response:
1179
+ if response.status == 200:
1180
+ data = await response.json()
1181
+ article_text = data["candidates"][0]["content"]["parts"][0]["text"]
1182
+ break
1183
+ except Exception: continue
1184
+
1185
+ # Fallback to Hugging Face
1186
+ if not article_text and HF_TOKENS:
1187
+ keys_to_try_hf = HF_TOKENS.copy()
1188
+ random.shuffle(keys_to_try_hf)
1189
+ async with aiohttp.ClientSession() as session:
1190
+ for hf_key in keys_to_try_hf:
1191
+ url = "https://router.huggingface.co/v1/chat/completions"
1192
+ headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1193
+ payload = {
1194
+ "model": "google/gemma-4-31B-it:novita",
1195
+ "messages":[{"role": "user", "content":[{"type": "text", "text": ai_prompt}]}],
1196
+ "max_tokens": 4096
1197
+ }
1198
+ try:
1199
+ async with session.post(url, headers=headers, json=payload, timeout=60) as response:
1200
+ if response.status == 200:
1201
+ data = await response.json()
1202
+ article_text = data["choices"][0]["message"]["content"]
1203
+ break
1204
+ except Exception: continue
1205
+
1206
+ if not article_text:
1207
+ return await send_with_keyboard(client, chat_id, "❌ سرور تولید ��تن شلوغ است، لطفاً بعداً تلاش کنید.", True)
1208
+
1209
+ try:
1210
+ if proc_msg:
1211
+ msg_id = getattr(proc_msg, 'message_id', None)
1212
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1213
+ if msg_id: await client.delete_messages(chat_id,[msg_id])
1214
+ except Exception: pass
1215
+
1216
+ proc_msg = await send_with_keyboard(client, chat_id, "📄 مقاله با موفقیت نوشته شد! در حال ارتباط با سرور و تبدیل به فایل‌های PDF و Word...\n(لطفا صبور باشید)", False)
1217
+
1218
+ pdf_bytes = None
1219
+ docx_bytes = None
1220
+ converter_url = "https://opera8-texttopdf.hf.space/"
1221
+
1222
+ async with aiohttp.ClientSession() as session:
1223
+ # دریافت خروجی PDF
1224
+ try:
1225
+ form_data_pdf = aiohttp.FormData()
1226
+ form_data_pdf.add_field('content', article_text)
1227
+ form_data_pdf.add_field('format', 'pdf')
1228
+ async with session.post(converter_url, data=form_data_pdf, timeout=60) as resp:
1229
+ if resp.status == 200:
1230
+ pdf_bytes = await resp.read()
1231
+ except Exception as e: print("PDF creation error:", e)
1232
+
1233
+ # دریافت خروجی DOCX
1234
+ try:
1235
+ form_data_docx = aiohttp.FormData()
1236
+ form_data_docx.add_field('content', article_text)
1237
+ form_data_docx.add_field('format', 'docx')
1238
+ async with session.post(converter_url, data=form_data_docx, timeout=60) as resp:
1239
+ if resp.status == 200:
1240
+ docx_bytes = await resp.read()
1241
+ except Exception as e: print("DOCX creation error:", e)
1242
+
1243
+ try:
1244
+ if proc_msg:
1245
+ msg_id = getattr(proc_msg, 'message_id', None)
1246
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1247
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
1248
+ except Exception: pass
1249
+
1250
+ if not pdf_bytes and not docx_bytes:
1251
+ return await send_with_keyboard(client, chat_id, "❌ متاسفانه در تبدیل متن به فایل خطایی رخ داد.", True)
1252
+
1253
+ # کسر اعتبار ساخت فایل از سهمیه "چت" کاربر در صورت غیر پرمیوم بودن
1254
+ if not creds.get("is_premium"):
1255
+ user_credits_db[str_chat_id]["chat"] -= 1
1256
+ save_db(user_credits_db)
1257
+
1258
+ uid = uuid.uuid4().hex
1259
+ pdf_filename = f"Article_{uid}.pdf"
1260
+ docx_filename = f"Article_{uid}.docx"
1261
+
1262
+ uploaded_any = False
1263
+
1264
+ if pdf_bytes:
1265
+ with open(pdf_filename, "wb") as f:
1266
+ f.write(pdf_bytes)
1267
+ res = await helper_upload_file(client, chat_id, pdf_filename, "File", f"📄 فایل PDF مقاله شما:\n\n💡 موضوع: {topic}")
1268
+ if res is True: uploaded_any = True
1269
+ if os.path.exists(pdf_filename): os.remove(pdf_filename)
1270
+ await asyncio.sleep(1.5)
1271
+
1272
+ if docx_bytes:
1273
+ with open(docx_filename, "wb") as f:
1274
+ f.write(docx_bytes)
1275
+ res = await helper_upload_file(client, chat_id, docx_filename, "File", f"📝 فایل Word (DOCX) مقاله شما:\n\n💡 موضوع: {topic}")
1276
+ if res is True: uploaded_any = True
1277
+ if os.path.exists(docx_filename): os.remove(docx_filename)
1278
+
1279
+ if uploaded_any:
1280
+ await send_with_keyboard(client, chat_id, "✅ مقاله شما با موفقیت به صورت فایل تحویل داده شد!", True)
1281
+ else:
1282
+ await send_with_keyboard(client, chat_id, "❌ فایل‌ها ساخته شدند اما روبیکا در ارسال آن‌ها دچار مشکل شد.", True)
1283
+
1284
+
1285
  # --- تنظیمات ربات روبیکا ---
1286
  if not bot_token:
1287
  print("خطا: توکن ربات روبیکا وارد نشده است!")
1288
  else:
1289
  bot = BotClient(bot_token)
1290
 
1291
+ @bot.on_update(filters.private)
1292
  async def main_handler(client, update):
1293
  global BOT_GUID
1294
 
 
1642
  await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1643
  return
1644
 
1645
+ if user_text_str in["/create_file", "ساخت فایل 📄"]:
1646
+ user_states[chat_id]["mode"] = "create_file_waiting_for_topic"
1647
+ await send_with_keyboard(client, chat_id, "📄 شما وارد بخش **ساخت فایل** شدید.\n\nلطفاً موضوع مقاله‌ای که می‌خواهید را کامل بفرستید.\nمثال: نحوه مدیریت زمان\n\nهوش مصنوعی یک مقاله کامل و طولانی نوشته و در نهایت فایل PDF و Word آن را به شما تحویل می‌دهد.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1648
+ return
1649
+
1650
  current_mode = user_states[chat_id].get("mode")
1651
 
1652
  if current_mode is None:
 
1756
  else: await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1757
  return
1758
 
1759
+ elif current_mode == "create_file_waiting_for_topic":
1760
+ if user_text_str:
1761
+ asyncio.create_task(process_create_file(client, chat_id, user_text_str))
1762
+ else:
1763
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً موضوع مقاله خود را به صورت متنی بفرستید.", False)
1764
+ return
1765
+
1766
  except Exception: traceback.print_exc()
1767
 
1768
  if __name__ == "__main__":