Opera8 commited on
Commit
c29619c
·
verified ·
1 Parent(s): 3dd2bff

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +249 -90
main.py CHANGED
@@ -4,6 +4,7 @@ import random
4
  import aiohttp
5
  import traceback
6
  import asyncio
 
7
  from flask import Flask
8
  from rubpy.bot import BotClient, filters
9
 
@@ -16,7 +17,7 @@ app = Flask(__name__)
16
 
17
  @app.route('/')
18
  def home():
19
- return "ربات یکپارچه آلفا (نسخه دارای حافظه و چت خالص) روشن است! 🚀"
20
 
21
  def run_flask():
22
  app.run(host="0.0.0.0", port=7860)
@@ -40,6 +41,16 @@ MAIN_KEYPAD_DICT = {
40
  {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا با هوش مصنوعی🎙️"}
41
  ]
42
  },
 
 
 
 
 
 
 
 
 
 
43
  {
44
  "buttons": [
45
  {"id": "cancel_btn", "type": "Simple", "button_text": "برگشت♻️"}
@@ -54,8 +65,8 @@ MAIN_KEYPAD_DICT = {
54
  async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
55
  if not use_keyboard:
56
  # ارسال پیام متنی خالص بدون دستکاری کیبورد
57
- await client.send_message(chat_id, text)
58
- return
59
 
60
  # ارسال تهاجمی: دور زدن محدودیت‌های rubpy
61
  try:
@@ -65,17 +76,18 @@ async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
65
  "chat_keypad_type": "New",
66
  "chat_keypad": MAIN_KEYPAD_DICT
67
  }
68
- await client._make_request("sendMessage", payload)
69
- return
70
  except Exception as raw_api_err:
71
  try:
72
- await client.send_message(chat_id, text, chat_keypad=MAIN_KEYPAD_DICT, chat_keypad_type="New")
73
- return
74
  except Exception as standard_err:
75
  pass
76
 
77
  # اگر تمامی روش‌ها شکست خورد، فقط پیام ارسال شود
78
- await client.send_message(chat_id, text)
 
79
 
80
 
81
  # --- لیست تمام سرورهای تولید صدای شما ---
@@ -114,25 +126,25 @@ HF_TOKENS = [k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
114
  user_states = {}
115
 
116
 
117
- # --- ۱. پردازش چت متنی در پس‌زمینه (با سیستم حافظه و بدون پیام اضافه) ---
118
  async def process_gemini(client, chat_id, prompt):
119
  if not GEMINI_KEYS:
120
  await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
121
  return
122
 
 
 
 
123
  # استخراج تاریخچه مکالمات کاربر
124
  history = user_states[chat_id].get("history", [])
125
 
126
- # اطمینان از ساختار استاندارد جیمینای (جلوگیری از ارور ارسال دو پیام پشت سر هم توسط کاربر)
127
  if history and history[-1]["role"] == "user":
128
  history[-1]["parts"][0]["text"] += "\n" + prompt
129
  else:
130
  history.append({"role": "user", "parts": [{"text": prompt}]})
131
 
132
- # نگه داشتن فقط 10 پیام آخر (برای جلوگیری از سنگین شدن درخواست و تایم‌اوت)
133
  if len(history) > 10:
134
  history = history[-10:]
135
- # جیمینای همیشه باید با پیام user شروع کند
136
  if history[0]["role"] == "model":
137
  history = history[1:]
138
 
@@ -143,7 +155,6 @@ async def process_gemini(client, chat_id, prompt):
143
  async with aiohttp.ClientSession() as session:
144
  for key in keys_to_try:
145
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
146
- # ارسال تاریخچه به جای یک پیام تکی
147
  payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
148
  try:
149
  async with session.post(url, json=payload, timeout=45) as response:
@@ -159,18 +170,26 @@ async def process_gemini(client, chat_id, prompt):
159
  except Exception as e:
160
  continue
161
 
 
 
 
 
 
 
 
 
 
 
 
162
  if not final_answer:
163
- # اگر پاسخ نگرفتیم، پیام آخر کاربر را از حافظه پاک می‌کنیم تا خراب نشود
164
  if history and history[-1]["role"] == "user":
165
  history.pop()
166
  await send_with_keyboard(client, chat_id, "❌ متأسفانه در حال حاضر پاسخی دریافت نشد. لطفاً دوباره تلاش کنید.", False)
167
  return
168
 
169
- # ذخیره پاسخ هوش مصنوعی در حافظه
170
  history.append({"role": "model", "parts": [{"text": final_answer}]})
171
  user_states[chat_id]["history"] = history
172
 
173
- # تکه‌تکه کردن متن‌های طولانی برای ارسال در روبیکا
174
  try:
175
  max_len = 1000
176
  chunks = []
@@ -194,7 +213,6 @@ async def process_gemini(client, chat_id, prompt):
194
  chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇"
195
 
196
  try:
197
- # ارسال خالص پیام بدون درخواست نمایش مجدد کیبورد
198
  await send_with_keyboard(client, chat_id, chunk, False)
199
  await asyncio.sleep(2.5)
200
  except Exception as send_err:
@@ -207,10 +225,10 @@ async def process_gemini(client, chat_id, prompt):
207
  # --- ۲. پردازش ساخت عکس در پس‌زمینه ---
208
  async def process_image(client, chat_id, prompt):
209
  if not HF_TOKENS:
210
- await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس (HF_TOKENS) در تنظیمات سرور ثبت نشده‌اند.", False)
211
  return
212
 
213
- await send_with_keyboard(client, chat_id, "🎨 در حال طراحی عکس...\n(ممکن است چند ثانیه زمان ببرد)", False)
214
 
215
  keys_to_try = HF_TOKENS.copy()
216
  random.shuffle(keys_to_try)
@@ -227,9 +245,18 @@ async def process_image(client, chat_id, prompt):
227
  last_error_log = str(e)
228
  continue
229
 
 
 
 
 
 
 
 
 
 
 
230
  if not generated_image:
231
- error_msg = f"❌ متأسفانه عکس ساخته نشد.\n\n⚠️ خطای توکن‌ها:\n{last_error_log[:200]}"
232
- await send_with_keyboard(client, chat_id, error_msg, False)
233
  return
234
 
235
  try:
@@ -241,53 +268,31 @@ async def process_image(client, chat_id, prompt):
241
  caption_text = "🎨 تصویر شما آماده شد!\n(مدل: Z-Image-Turbo)"
242
 
243
  uploaded_directly = False
244
- error_logs = []
245
-
246
  try:
247
  await client.send_photo(chat_id, file_name)
248
  uploaded_directly = True
249
- except Exception as e1:
250
- error_logs.append(f"send_photo: {e1}")
251
-
252
- if not uploaded_directly:
253
- try:
254
- await client.send_image(chat_id, file_name)
255
- uploaded_directly = True
256
- except Exception as e2:
257
- error_logs.append(f"send_image: {e2}")
258
-
259
- if not uploaded_directly:
260
  try:
261
  await client.send_document(chat_id, file_name)
262
  uploaded_directly = True
263
- except Exception as e3:
264
- error_logs.append(f"send_document: {e3}")
265
-
266
- if not uploaded_directly:
267
- try:
268
- await client.send_file(chat_id, file_name)
269
- uploaded_directly = True
270
- except Exception as e4:
271
- error_logs.append(f"send_file: {e4}")
272
 
273
  if uploaded_directly:
274
- await send_with_keyboard(client, chat_id, caption_text, False)
275
  else:
276
- err_details = " | ".join(error_logs)
277
- err_msg = f"❌ تصویر ساخته شد اما روبیکا اجازه آپلود نداد!\n\n🔴 لاگ خطای واقعی:\n`{err_details[:800]}`"
278
- await send_with_keyboard(client, chat_id, err_msg, False)
279
 
280
  if os.path.exists(file_name):
281
  os.remove(file_name)
282
 
283
  except Exception as e:
284
- await send_with_keyboard(client, chat_id, "❌ خطایی در فرآیند ذخیره عکس رخ داد.", False)
285
 
286
 
287
  # --- ۳. پردازش ساخت صدا در پس‌زمینه (TTS) ---
288
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
289
  try:
290
- await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(بسته به طول متن ممکن است چند دقیقه طول بکشد، صبور باشید)", False)
291
 
292
  payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
293
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
@@ -319,6 +324,16 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
319
  last_error = f"خطا در ارتباط: {str(e)}"
320
  continue
321
 
 
 
 
 
 
 
 
 
 
 
322
  if audio_bytes:
323
  file_name = f"audio_{random.randint(1000, 999999)}.wav"
324
  with open(file_name, "wb") as f:
@@ -326,43 +341,128 @@ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
326
 
327
  caption_text = "✅ پردازش صدا انجام شد."
328
  uploaded_directly = False
329
- error_logs = []
330
 
331
  try:
332
  await client.send_voice(chat_id, file_name)
333
  uploaded_directly = True
334
- except Exception as e1:
335
- error_logs.append(f"send_voice: {e1}")
336
-
337
- if not uploaded_directly:
338
  try:
339
  await client.send_audio(chat_id, file_name)
340
  uploaded_directly = True
341
- except Exception as e2:
342
- error_logs.append(f"send_audio: {e2}")
343
-
344
- if not uploaded_directly:
345
- try:
346
- await client.send_document(chat_id, file_name)
347
- uploaded_directly = True
348
- except Exception as e3:
349
- error_logs.append(f"send_document: {e3}")
350
 
351
  if uploaded_directly:
352
- await send_with_keyboard(client, chat_id, caption_text, False)
353
  else:
354
- err_details = " | ".join(error_logs)
355
- await send_with_keyboard(client, chat_id, f"❌ صدا ساخته شد اما روبیکا اجازه آپلود نداد!\n\n🔴 لاگ خطا:\n`{err_details[:700]}`", False)
356
 
357
  if os.path.exists(file_name):
358
  os.remove(file_name)
359
  else:
360
- await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", False)
361
 
362
  except Exception as e:
363
  traceback.print_exc()
364
 
365
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
  # --- تنظیمات ربات روبیکا ---
367
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
368
 
@@ -374,32 +474,35 @@ else:
374
  @bot.on_update(filters.private)
375
  async def main_handler(client, update):
376
  try:
 
377
  user_text = getattr(update, "text", "") or getattr(getattr(update, "message", None), "text", "") or getattr(getattr(update, "new_message", None), "text", "")
378
  user_text_str = str(user_text).strip() if user_text else ""
379
-
380
- if not user_text_str:
381
- return
 
 
 
 
382
 
383
  chat_id = getattr(update, "chat_id", None) or getattr(update, "author_guid", None) or getattr(update, "object_guid", None)
384
  if not chat_id:
385
  return
386
 
387
  if chat_id not in user_states:
388
- # مقداردهی اولیه سیستم حافظه برای کار��ر
389
- user_states[chat_id] = {"mode": None, "text": "", "history": []}
390
 
391
- # لغو عملیات و پاک کردن کامل حافظه
392
  if user_text_str in ["/start", "سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
393
- user_states[chat_id] = {"mode": None, "text": "", "history": []}
394
  menu = (
395
  "سلام! به ربات هوشمند آلفا خوش آمدید 🤖\n\n"
396
- "لطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:\n"
397
  )
398
  await send_with_keyboard(client, chat_id, menu, True)
399
  return
400
 
401
  if user_text_str in ["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
402
- # شروع چت و پاک کردن تاریخچه قبلی
403
  user_states[chat_id] = {"mode": "chat", "text": "", "history": []}
404
  await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n(حالا ربات سابقه گفتگو را به یاد می‌آورد)\n\nهر سوالی دارید بفرستید تا جواب بدم:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
405
  return
@@ -414,29 +517,46 @@ else:
414
  await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید (حداکثر 2500 کاراکتر):\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
415
  return
416
 
 
 
 
 
 
 
 
 
 
 
417
  current_mode = user_states[chat_id].get("mode")
418
 
419
  if current_mode is None:
420
- await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
 
 
 
421
  return
422
 
 
423
  elif current_mode == "chat":
424
- asyncio.create_task(process_gemini(client, chat_id, user_text_str))
 
425
  return
426
 
427
  elif current_mode == "image_waiting_for_text":
428
- asyncio.create_task(process_image(client, chat_id, user_text_str))
 
429
  return
430
 
431
  elif current_mode == "tts_waiting_for_text":
432
- if len(user_text_str) > 2500:
433
- await send_with_keyboard(client, chat_id, "⚠️ متن طولانی است. لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
434
- return
435
-
436
- user_states[chat_id]["text"] = user_text_str
437
- user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
438
-
439
- speakers_menu = """✅ متن شما ذخیره شد.
 
440
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
441
 
442
  1. شهاب | 2. آوا | 3. نوید
@@ -449,22 +569,61 @@ else:
449
  22. ترانه | 23. نیکو | 24. هستی
450
  25. کامیار| 26. کیانوش| 27. پویا
451
  28. مهتاب | 29. سام | 30. لیدا"""
452
- await send_with_keyboard(client, chat_id, speakers_menu, False)
453
  return
454
 
455
  elif current_mode == "tts_waiting_for_speaker":
456
  if user_text_str.isdigit() and user_text_str in SPEAKERS:
457
  speaker_name, speaker_id = SPEAKERS[user_text_str]
458
  saved_text = user_states[chat_id]["text"]
459
-
460
  user_states[chat_id]["mode"] = "tts_waiting_for_text"
461
  user_states[chat_id]["text"] = ""
462
-
463
  asyncio.create_task(process_tts(client, chat_id, saved_text, speaker_id, speaker_name))
464
  else:
465
  await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
466
  return
467
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  except Exception as e:
469
  traceback.print_exc()
470
 
 
4
  import aiohttp
5
  import traceback
6
  import asyncio
7
+ import base64
8
  from flask import Flask
9
  from rubpy.bot import BotClient, filters
10
 
 
17
 
18
  @app.route('/')
19
  def home():
20
+ return "ربات یکپارچه آلفا (نسخه پرو با تحلیل فایل و STT) روشن است! 🚀"
21
 
22
  def run_flask():
23
  app.run(host="0.0.0.0", port=7860)
 
41
  {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا با هوش مصنوعی🎙️"}
42
  ]
43
  },
44
+ {
45
+ "buttons": [
46
+ {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل با هوش مصنوعی 📁"}
47
+ ]
48
+ },
49
+ {
50
+ "buttons": [
51
+ {"id": "stt_btn", "type": "Simple", "button_text": "تبدیل فایل صوتی به متن 📝"}
52
+ ]
53
+ },
54
  {
55
  "buttons": [
56
  {"id": "cancel_btn", "type": "Simple", "button_text": "برگشت♻️"}
 
65
  async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
66
  if not use_keyboard:
67
  # ارسال پیام متنی خالص بدون دستکاری کیبورد
68
+ msg = await client.send_message(chat_id, text)
69
+ return msg
70
 
71
  # ارسال تهاجمی: دور زدن محدودیت‌های rubpy
72
  try:
 
76
  "chat_keypad_type": "New",
77
  "chat_keypad": MAIN_KEYPAD_DICT
78
  }
79
+ msg = await client._make_request("sendMessage", payload)
80
+ return msg
81
  except Exception as raw_api_err:
82
  try:
83
+ msg = await client.send_message(chat_id, text, chat_keypad=MAIN_KEYPAD_DICT, chat_keypad_type="New")
84
+ return msg
85
  except Exception as standard_err:
86
  pass
87
 
88
  # اگر تمامی روش‌ها شکست خورد، فقط پیام ارسال شود
89
+ msg = await client.send_message(chat_id, text)
90
+ return msg
91
 
92
 
93
  # --- لیست تمام سرورهای تولید صدای شما ---
 
126
  user_states = {}
127
 
128
 
129
+ # --- ۱. پردازش چت متنی در پس‌زمینه (با حذف پیام پردازش) ---
130
  async def process_gemini(client, chat_id, prompt):
131
  if not GEMINI_KEYS:
132
  await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
133
  return
134
 
135
+ # ارسال پیام موقت "در حال پردازش..."
136
+ proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
137
+
138
  # استخراج تاریخچه مکالمات کاربر
139
  history = user_states[chat_id].get("history", [])
140
 
 
141
  if history and history[-1]["role"] == "user":
142
  history[-1]["parts"][0]["text"] += "\n" + prompt
143
  else:
144
  history.append({"role": "user", "parts": [{"text": prompt}]})
145
 
 
146
  if len(history) > 10:
147
  history = history[-10:]
 
148
  if history[0]["role"] == "model":
149
  history = history[1:]
150
 
 
155
  async with aiohttp.ClientSession() as session:
156
  for key in keys_to_try:
157
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
 
158
  payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
159
  try:
160
  async with session.post(url, json=payload, timeout=45) as response:
 
170
  except Exception as e:
171
  continue
172
 
173
+ # 🔴 پاک کردن پیام موقت "در حال پردازش..."
174
+ try:
175
+ if proc_msg:
176
+ msg_id = getattr(proc_msg, 'message_id', None)
177
+ if isinstance(proc_msg, dict):
178
+ msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
179
+ if msg_id:
180
+ await client.delete_messages(chat_id, [msg_id])
181
+ except Exception as e:
182
+ print(f"Failed to delete processing msg: {e}")
183
+
184
  if not final_answer:
 
185
  if history and history[-1]["role"] == "user":
186
  history.pop()
187
  await send_with_keyboard(client, chat_id, "❌ متأسفانه در حال حاضر پاسخی دریافت نشد. لطفاً دوباره تلاش کنید.", False)
188
  return
189
 
 
190
  history.append({"role": "model", "parts": [{"text": final_answer}]})
191
  user_states[chat_id]["history"] = history
192
 
 
193
  try:
194
  max_len = 1000
195
  chunks = []
 
213
  chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇"
214
 
215
  try:
 
216
  await send_with_keyboard(client, chat_id, chunk, False)
217
  await asyncio.sleep(2.5)
218
  except Exception as send_err:
 
225
  # --- ۲. پردازش ساخت عکس در پس‌زمینه ---
226
  async def process_image(client, chat_id, prompt):
227
  if not HF_TOKENS:
228
+ await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
229
  return
230
 
231
+ proc_msg = await send_with_keyboard(client, chat_id, "🎨 در حال طراحی عکس...\n(ممکن است چند ثانیه زمان ببرد)", False)
232
 
233
  keys_to_try = HF_TOKENS.copy()
234
  random.shuffle(keys_to_try)
 
245
  last_error_log = str(e)
246
  continue
247
 
248
+ # پاک کردن پیام موقت
249
+ try:
250
+ if proc_msg:
251
+ msg_id = getattr(proc_msg, 'message_id', None)
252
+ if isinstance(proc_msg, dict):
253
+ msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
254
+ if msg_id:
255
+ await client.delete_messages(chat_id, [msg_id])
256
+ except Exception: pass
257
+
258
  if not generated_image:
259
+ await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
 
260
  return
261
 
262
  try:
 
268
  caption_text = "🎨 تصویر شما آماده شد!\n(مدل: Z-Image-Turbo)"
269
 
270
  uploaded_directly = False
 
 
271
  try:
272
  await client.send_photo(chat_id, file_name)
273
  uploaded_directly = True
274
+ except Exception:
 
 
 
 
 
 
 
 
 
 
275
  try:
276
  await client.send_document(chat_id, file_name)
277
  uploaded_directly = True
278
+ except Exception: pass
 
 
 
 
 
 
 
 
279
 
280
  if uploaded_directly:
281
+ await send_with_keyboard(client, chat_id, caption_text, True)
282
  else:
283
+ await send_with_keyboard(client, chat_id, " تصویر ساخته شد اما روبیکا اجازه آپلود نداد!", True)
 
 
284
 
285
  if os.path.exists(file_name):
286
  os.remove(file_name)
287
 
288
  except Exception as e:
289
+ await send_with_keyboard(client, chat_id, "❌ خطایی در فرآیند ذخیره عکس رخ داد.", True)
290
 
291
 
292
  # --- ۳. پردازش ساخت صدا در پس‌زمینه (TTS) ---
293
  async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
294
  try:
295
+ proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
296
 
297
  payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
298
  headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
 
324
  last_error = f"خطا در ارتباط: {str(e)}"
325
  continue
326
 
327
+ # پاک کردن پیام موقت
328
+ try:
329
+ if proc_msg:
330
+ msg_id = getattr(proc_msg, 'message_id', None)
331
+ if isinstance(proc_msg, dict):
332
+ msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
333
+ if msg_id:
334
+ await client.delete_messages(chat_id, [msg_id])
335
+ except Exception: pass
336
+
337
  if audio_bytes:
338
  file_name = f"audio_{random.randint(1000, 999999)}.wav"
339
  with open(file_name, "wb") as f:
 
341
 
342
  caption_text = "✅ پردازش صدا انجام شد."
343
  uploaded_directly = False
 
344
 
345
  try:
346
  await client.send_voice(chat_id, file_name)
347
  uploaded_directly = True
348
+ except Exception:
 
 
 
349
  try:
350
  await client.send_audio(chat_id, file_name)
351
  uploaded_directly = True
352
+ except Exception: pass
 
 
 
 
 
 
 
 
353
 
354
  if uploaded_directly:
355
+ await send_with_keyboard(client, chat_id, caption_text, True)
356
  else:
357
+ await send_with_keyboard(client, chat_id, f" صدا ساخته شد اما روبیکا اجازه آپلود نداد!\n\n🔴 دلیل: {last_error}", True)
 
358
 
359
  if os.path.exists(file_name):
360
  os.remove(file_name)
361
  else:
362
+ await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
363
 
364
  except Exception as e:
365
  traceback.print_exc()
366
 
367
 
368
+ # --- ۴. پردازش تبدیل فایل صوتی به متن (STT) ---
369
+ async def process_stt(client, chat_id, audio_bytes):
370
+ if not HF_TOKENS:
371
+ await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
372
+ return
373
+
374
+ proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن... (لطفاً صبور باشید)", False)
375
+
376
+ keys_to_try = HF_TOKENS.copy()
377
+ random.shuffle(keys_to_try)
378
+
379
+ transcribed_text = None
380
+ last_error_log = "ناموفق"
381
+
382
+ for token in keys_to_try:
383
+ try:
384
+ # استفاده از مدل قدرتمند ویسپر برای تبدیل صدا به متن (پشتیبانی عالی از فارسی)
385
+ hf_client = AsyncInferenceClient(provider="hf-inference", api_key=token)
386
+ response = await hf_client.automatic_speech_recognition(audio_bytes, model="openai/whisper-large-v3-turbo")
387
+ transcribed_text = response.text
388
+ break
389
+ except Exception as e:
390
+ last_error_log = str(e)
391
+ continue
392
+
393
+ # پاک کردن پیام موقت
394
+ try:
395
+ if proc_msg:
396
+ msg_id = getattr(proc_msg, 'message_id', None)
397
+ if isinstance(proc_msg, dict):
398
+ msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
399
+ if msg_id:
400
+ await client.delete_messages(chat_id, [msg_id])
401
+ except Exception: pass
402
+
403
+ if transcribed_text:
404
+ await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
405
+ else:
406
+ await send_with_keyboard(client, chat_id, f"❌ متأسفانه تبدیل صدا به متن ناموفق بود.\n\n⚠️ دلیل: {last_error_log[:150]}", True)
407
+
408
+
409
+ # --- ۵. پردازش تحلیل فایل (عکس) با جیمینای ---
410
+ async def process_file_analysis(client, chat_id, file_bytes, prompt):
411
+ if not GEMINI_KEYS:
412
+ await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
413
+ return
414
+
415
+ proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل و بررسی فایل...", False)
416
+
417
+ # تبدیل فایل به base64 برای ارسال به جیمینای
418
+ base64_data = base64.b64encode(file_bytes).decode('utf-8')
419
+
420
+ keys_to_try = GEMINI_KEYS.copy()
421
+ random.shuffle(keys_to_try)
422
+ final_answer = None
423
+
424
+ async with aiohttp.ClientSession() as session:
425
+ for key in keys_to_try:
426
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
427
+ payload = {
428
+ "contents": [{
429
+ "parts": [
430
+ {"text": prompt},
431
+ {"inlineData": {"mimeType": "image/jpeg", "data": base64_data}}
432
+ ]
433
+ }],
434
+ "generationConfig": {"temperature": 0.6, "maxOutputTokens": 8192}
435
+ }
436
+ try:
437
+ async with session.post(url, json=payload, timeout=45) as response:
438
+ if response.status == 200:
439
+ data = await response.json()
440
+ try:
441
+ final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
442
+ break
443
+ except (KeyError, IndexError):
444
+ continue
445
+ else:
446
+ continue
447
+ except Exception as e:
448
+ continue
449
+
450
+ # پاک کردن پیام موقت
451
+ try:
452
+ if proc_msg:
453
+ msg_id = getattr(proc_msg, 'message_id', None)
454
+ if isinstance(proc_msg, dict):
455
+ msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
456
+ if msg_id:
457
+ await client.delete_messages(chat_id, [msg_id])
458
+ except Exception: pass
459
+
460
+ if final_answer:
461
+ await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
462
+ else:
463
+ await send_with_keyboard(client, chat_id, "❌ متأسفانه در حال حاضر پاسخی برای این فایل دریافت نشد.", True)
464
+
465
+
466
  # --- تنظیمات ربات روبیکا ---
467
  bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
468
 
 
474
  @bot.on_update(filters.private)
475
  async def main_handler(client, update):
476
  try:
477
+ # استخراج اطلاعات پیام
478
  user_text = getattr(update, "text", "") or getattr(getattr(update, "message", None), "text", "") or getattr(getattr(update, "new_message", None), "text", "")
479
  user_text_str = str(user_text).strip() if user_text else ""
480
+
481
+ # بررسی وجود فایل پیوست در پیام
482
+ is_file = False
483
+ msg_obj = getattr(update, "message", None) or getattr(update, "new_message", None)
484
+ if msg_obj:
485
+ if getattr(msg_obj, "file_inline", None) or getattr(msg_obj, "photo", None) or getattr(msg_obj, "voice", None) or getattr(msg_obj, "audio", None) or getattr(msg_obj, "document", None):
486
+ is_file = True
487
 
488
  chat_id = getattr(update, "chat_id", None) or getattr(update, "author_guid", None) or getattr(update, "object_guid", None)
489
  if not chat_id:
490
  return
491
 
492
  if chat_id not in user_states:
493
+ user_states[chat_id] = {"mode": None, "text": "", "history": [], "file_bytes": None}
 
494
 
495
+ # مدیریت کامندهای لغو/شروع از دکمه‌ها یا چت
496
  if user_text_str in ["/start", "سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
497
+ user_states[chat_id] = {"mode": None, "text": "", "history": [], "file_bytes": None}
498
  menu = (
499
  "سلام! به ربات هوشمند آلفا خوش آمدید 🤖\n\n"
500
+ "لطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:"
501
  )
502
  await send_with_keyboard(client, chat_id, menu, True)
503
  return
504
 
505
  if user_text_str in ["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
 
506
  user_states[chat_id] = {"mode": "chat", "text": "", "history": []}
507
  await send_with_keyboard(client, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n(حالا ربات سابقه گفتگو را به یاد می‌آورد)\n\nهر سوالی دارید بفرستید تا جواب بدم:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
508
  return
 
517
  await send_with_keyboard(client, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید (حداکثر 2500 کاراکتر):\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
518
  return
519
 
520
+ if user_text_str in ["/file", "تحلیل فایل با هوش مصنوعی 📁"]:
521
+ user_states[chat_id] = {"mode": "file_waiting_for_file", "text": "", "history": [], "file_bytes": None}
522
+ await send_with_keyboard(client, chat_id, "📁 شما وارد بخش **تحلیل فایل** شدید.\n\nلطفاً فایل (ترجیحاً عکس) خود را ارسال کنید:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
523
+ return
524
+
525
+ if user_text_str in ["/stt", "تبدیل فایل صوتی به متن 📝"]:
526
+ user_states[chat_id] = {"mode": "stt_waiting_for_audio", "text": "", "history": []}
527
+ await send_with_keyboard(client, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل صوتی (آهنگ یا ویس) خود را فوروارد یا ارسال کنید:\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
528
+ return
529
+
530
  current_mode = user_states[chat_id].get("mode")
531
 
532
  if current_mode is None:
533
+ if is_file:
534
+ pass # اگر حالت مشخص نیست فایل را نادیده بگیر
535
+ elif user_text_str:
536
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
537
  return
538
 
539
+ # --- مسیریابی بخش‌های مختلف ---
540
  elif current_mode == "chat":
541
+ if user_text_str:
542
+ asyncio.create_task(process_gemini(client, chat_id, user_text_str))
543
  return
544
 
545
  elif current_mode == "image_waiting_for_text":
546
+ if user_text_str:
547
+ asyncio.create_task(process_image(client, chat_id, user_text_str))
548
  return
549
 
550
  elif current_mode == "tts_waiting_for_text":
551
+ if user_text_str:
552
+ if len(user_text_str) > 2500:
553
+ await send_with_keyboard(client, chat_id, "⚠️ متن طولانی است. لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
554
+ return
555
+
556
+ user_states[chat_id]["text"] = user_text_str
557
+ user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
558
+
559
+ speakers_menu = """✅ متن شما ذخیره شد.
560
  لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
561
 
562
  1. شهاب | 2. آوا | 3. نوید
 
569
  22. ترانه | 23. نیکو | 24. هستی
570
  25. کامیار| 26. کیانوش| 27. پویا
571
  28. مهتاب | 29. سام | 30. لیدا"""
572
+ await send_with_keyboard(client, chat_id, speakers_menu, False)
573
  return
574
 
575
  elif current_mode == "tts_waiting_for_speaker":
576
  if user_text_str.isdigit() and user_text_str in SPEAKERS:
577
  speaker_name, speaker_id = SPEAKERS[user_text_str]
578
  saved_text = user_states[chat_id]["text"]
 
579
  user_states[chat_id]["mode"] = "tts_waiting_for_text"
580
  user_states[chat_id]["text"] = ""
 
581
  asyncio.create_task(process_tts(client, chat_id, saved_text, speaker_id, speaker_name))
582
  else:
583
  await send_with_keyboard(client, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
584
  return
585
 
586
+ # --- بخش جدید: STT (تبدیل صدا به متن) ---
587
+ elif current_mode == "stt_waiting_for_audio":
588
+ if not is_file:
589
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً فقط یک فایل صوتی (ویس یا موزیک) ارسال کنید.", False)
590
+ return
591
+
592
+ await send_with_keyboard(client, chat_id, "📥 در حال دانلود فایل صوتی...", False)
593
+ try:
594
+ audio_bytes = await client.download(msg_obj)
595
+ user_states[chat_id]["mode"] = "stt_waiting_for_audio" # آماده برای فایل بعدی
596
+ asyncio.create_task(process_stt(client, chat_id, audio_bytes))
597
+ except Exception as e:
598
+ await send_with_keyboard(client, chat_id, f"❌ خطا در دانلود فایل! لطفاً دوباره تلاش کنید.", False)
599
+ return
600
+
601
+ # --- بخش جدید: تحلیل فایل با هوش مصنوعی ---
602
+ elif current_mode == "file_waiting_for_file":
603
+ if not is_file:
604
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً ابتدا یک عکس/فایل ارسال کنید.", False)
605
+ return
606
+
607
+ await send_with_keyboard(client, chat_id, "📥 در حال دریافت فایل...", False)
608
+ try:
609
+ file_bytes = await client.download(msg_obj)
610
+ user_states[chat_id]["file_bytes"] = file_bytes
611
+ user_states[chat_id]["mode"] = "file_waiting_for_prompt"
612
+ await send_with_keyboard(client, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً بگویید **چگونه تحلیل شود؟** (مثلاً: متن داخل این عکس را استخراج کن، یا بگو در این عکس چیست؟)", False)
613
+ except Exception as e:
614
+ await send_with_keyboard(client, chat_id, f"❌ خطا در دریافت فایل! لطفاً دوباره تلاش کنید.", False)
615
+ return
616
+
617
+ elif current_mode == "file_waiting_for_prompt":
618
+ if user_text_str:
619
+ saved_bytes = user_states[chat_id].get("file_bytes")
620
+ user_states[chat_id]["mode"] = "file_waiting_for_file" # آماده برای فایل بعدی
621
+ user_states[chat_id]["file_bytes"] = None
622
+ asyncio.create_task(process_file_analysis(client, chat_id, saved_bytes, user_text_str))
623
+ else:
624
+ await send_with_keyboard(client, chat_id, "⚠️ لطفاً درخواست خود را به صورت متنی بنویسید.", False)
625
+ return
626
+
627
  except Exception as e:
628
  traceback.print_exc()
629