Opera8 commited on
Commit
9744adf
·
verified ·
1 Parent(s): be6645a

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +191 -122
main.py CHANGED
@@ -93,7 +93,7 @@ def gregorian_to_jalali(gy, gm, gd):
93
  return jy, jm, jd
94
 
95
  # ==============================================================================
96
- # 🟢 پارت 4: دیتابیس SQLite (نسخه فوق‌سریع Non-Blocking با سیستم Threading)
97
  # ==============================================================================
98
  import os
99
  import sqlite3
@@ -106,7 +106,7 @@ CORRUPT_FILE = "/data/users_db.db"
106
  BACKUP_JSON = "/data/users_db.json.bak"
107
 
108
  last_saved_state = {}
109
- # حافظه کش برای پیامهای پردازش شده جهت جلوگیری از قفل شدن دیتابیس
110
  recent_messages_dict = {}
111
  # قفل‌ها برای جلوگیری از تداخل رشته‌ها (Threads)
112
  db_lock = threading.Lock()
@@ -119,18 +119,26 @@ def init_sqlite_db():
119
 
120
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
121
  cursor = conn.cursor()
122
- # 🚀 تغییر بسیار مهم: استفاده از WAL به جای DELETE برای پشتیبانی از هزاران کاربر همزمان
 
123
  cursor.execute('PRAGMA journal_mode=WAL;')
124
  cursor.execute('PRAGMA synchronous=NORMAL;')
 
 
125
  cursor.execute('CREATE TABLE IF NOT EXISTS users (chat_id TEXT PRIMARY KEY, user_data TEXT)')
126
- cursor.execute('CREATE TABLE IF NOT EXISTS processed_messages (message_id TEXT PRIMARY KEY)')
 
 
127
  conn.commit()
 
 
 
 
128
  conn.close()
129
 
130
  if is_first_run:
131
  print("🚨 عملیات نجات آغاز شد...")
132
  restore_users_from_json()
133
- salvage_messages_from_corrupt_db()
134
 
135
  except Exception as e:
136
  print(f"❌ خطا در راه اندازی دیتابیس: {e}")
@@ -152,20 +160,6 @@ def restore_users_from_json():
152
  except Exception as e:
153
  print(f"❌ خطا در بازیابی اعتبارها: {e}")
154
 
155
- def salvage_messages_from_corrupt_db():
156
- if os.path.exists(CORRUPT_FILE):
157
- print(f"🔍 در حال تلاش برای نجات شناسه‌های پیام از فایل {CORRUPT_FILE} ...")
158
- try:
159
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
160
- conn.execute('PRAGMA journal_mode=WAL;')
161
- conn.execute(f"ATTACH DATABASE '{CORRUPT_FILE}' AS old_db")
162
- conn.execute("INSERT OR IGNORE INTO processed_messages SELECT message_id FROM old_db.processed_messages")
163
- conn.commit()
164
- conn.close()
165
- print("✅ شناسه‌های پیام قدیمی نجات یافتند.")
166
- except Exception as e:
167
- print(f"⚠️ هشدار فایل قدیمی: {e}")
168
-
169
  def load_db():
170
  global last_saved_state, recent_messages_dict
171
  init_sqlite_db()
@@ -175,25 +169,20 @@ def load_db():
175
  conn.execute('PRAGMA journal_mode=WAL;')
176
  cursor = conn.cursor()
177
 
178
- # لود کردن کاربران
179
  cursor.execute("SELECT chat_id, user_data FROM users")
180
  for row in cursor.fetchall():
181
  db_dict[row[0]] = json.loads(row[1])
182
 
183
- # 🚀 لود کردن 15 هزار پیام آخر به داخل RAM برای سرعت فوق العاده
184
- cursor.execute("SELECT message_id FROM processed_messages ORDER BY ROWID DESC LIMIT 15000")
185
- for row in cursor.fetchall():
186
- recent_messages_dict[row[0]] = True
187
-
188
  conn.close()
189
  last_saved_state = copy.deepcopy(db_dict)
190
- print(f"🚀 دیتابیس آماده شد. تعداد کاربران: {len(db_dict)} | پیام‌های کش شده در رم: {len(recent_messages_dict)}")
191
  return db_dict
192
  except Exception as e:
193
  print(f"⚠️ ارور در لود نهایی: {e}")
194
  return {}
195
 
196
- # --- سیستم ذخیره سازی در پس‌زمینه (بدون معطل کردن ربات) ---
197
  def background_save_worker(changed_data):
198
  with db_lock:
199
  try:
@@ -208,7 +197,7 @@ def background_save_worker(changed_data):
208
 
209
  def save_db(db_data):
210
  global last_saved_state
211
- changed =[]
212
  for cid, data in db_data.items():
213
  if cid not in last_saved_state or last_saved_state[cid] != data:
214
  changed.append((str(cid), json.dumps(data, ensure_ascii=False)))
@@ -219,36 +208,23 @@ def save_db(db_data):
219
  for cid, _ in changed:
220
  last_saved_state[cid] = copy.deepcopy(db_data[cid])
221
 
222
- # 🚀 پرتاب عملیات سنگین به یک پردازشگر دیگر تا ربات متوقف نشود
223
  threading.Thread(target=background_save_worker, args=(changed,), daemon=True).start()
224
 
225
- # --- سیستم بررسی پیام تکراری (کاملا منتقل شده به RAM سرور) ---
226
  def is_message_processed(message_id):
227
- # چک کردن داخل RAM (زمان اجرا: 0.0001 ثانیه)
228
  return str(message_id) in recent_messages_dict
229
 
230
- def background_mark_message(msg_id):
231
- with db_lock:
232
- try:
233
- conn = sqlite3.connect(DB_FILE, timeout=30.0)
234
- conn.execute('PRAGMA journal_mode=WAL;')
235
- conn.execute("INSERT OR IGNORE INTO processed_messages VALUES (?)", (msg_id,))
236
- conn.commit()
237
- conn.close()
238
- except: pass
239
-
240
  def mark_message_processed(message_id):
241
  msg_id_str = str(message_id)
242
  with msg_cache_lock:
243
- # ثبت در RAM
244
  recent_messages_dict[msg_id_str] = True
245
- # جلوگیری از پر شدن بیش از حد RAM
 
246
  if len(recent_messages_dict) > 15000:
247
  oldest_key = next(iter(recent_messages_dict))
248
  del recent_messages_dict[oldest_key]
249
-
250
- # ذخیره در دیتابیس به صورت پس‌زمینه
251
- threading.Thread(target=background_mark_message, args=(msg_id_str,), daemon=True).start()
252
 
253
  user_credits_db = load_db()
254
 
@@ -1001,24 +977,19 @@ async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, mo
1001
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1002
 
1003
  # ==============================================================================
1004
- # 🟢 پارت 13: پردازش هوش مصنوعی متنی و تصویری جیمینای و هاگینگ‌فیس
1005
  # ==============================================================================
1006
- # ==================================================================
1007
- # سایر توابع پردازشی
1008
- # ==================================================================
1009
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
1010
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1011
  creds = get_user_credits(str_chat_id)
1012
  if creds["chat"] <= 0:
1013
  return await send_with_keyboard(client, chat_id, "❌ اعتبار پیام‌های چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1014
 
1015
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
1016
-
1017
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
1018
- history = user_states[chat_id].get("history",[])
1019
- new_parts =[]
1020
 
1021
- is_image = True
1022
  has_non_image_file = False
1023
 
1024
  if prompt: new_parts.append({"text": prompt})
@@ -1043,91 +1014,188 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
1043
 
1044
  new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
1045
 
 
1046
  if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
1047
  else: history.append({"role": "user", "parts": new_parts})
1048
 
1049
- if len(history) > 40:
1050
- history = history[-40:]
 
1051
  if history[0]["role"] == "model": history = history[1:]
1052
 
1053
  final_answer = None
1054
- for attempt in range(3):
1055
- keys_to_try = get_next_gemini_keys(100)
1056
- async with aiohttp.ClientSession() as session:
1057
- for key in keys_to_try:
1058
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1059
- payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
1060
- try:
1061
- async with session.post(url, json=payload, timeout=60) as response:
1062
- if response.status == 200:
1063
- data = await response.json()
1064
- try:
1065
- final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
1066
- break
1067
- except (KeyError, IndexError): continue
1068
- except Exception: continue
1069
- if final_answer: break
1070
- await asyncio.sleep(2)
1071
 
1072
- if not final_answer:
1073
- if has_non_image_file:
1074
- if history and history[-1]["role"] == "user": history.pop()
 
 
1075
  try:
1076
  if proc_msg:
1077
  msg_id = getattr(proc_msg, 'message_id', None)
1078
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1079
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1080
  except Exception: pass
1081
- await send_with_keyboard(client, chat_id, "❌ متأسفانه سرور اصلی در حال حاضر شلوغ است و در این شرایط **فعلاً تنها امکان تحلیل تصاویر** توسط سرور جایگزین در دسترس است.", False)
1082
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1083
 
1084
- if HF_TOKENS:
1085
- hf_messages =[]
1086
- for msg in history:
1087
- role = "assistant" if msg["role"] == "model" else "user"
1088
- content_parts =[]
1089
- for part in msg["parts"]:
1090
- if "text" in part:
1091
- content_parts.append({"type": "text", "text": part["text"]})
1092
- elif "inlineData" in part:
1093
- mime_t = part["inlineData"]["mimeType"]
1094
- b64_d = part["inlineData"]["data"]
1095
- if mime_t.startswith('image/'):
1096
- content_parts.append({
1097
- "type": "image_url",
1098
- "image_url": {"url": f"data:{mime_t};base64,{b64_d}"}
1099
- })
1100
- if content_parts:
1101
- hf_messages.append({"role": role, "content": content_parts})
1102
 
1103
- for attempt in range(3):
1104
- keys_to_try_hf = HF_TOKENS.copy()
1105
- random.shuffle(keys_to_try_hf)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1106
  async with aiohttp.ClientSession() as session:
1107
- for hf_key in keys_to_try_hf:
1108
- url = "https://router.huggingface.co/v1/chat/completions"
1109
- headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1110
- payload = {
1111
- "model": "google/gemma-4-31B-it:novita",
1112
- "messages": hf_messages,
1113
- "max_tokens": 4096
1114
- }
1115
- try:
1116
- async with session.post(url, headers=headers, json=payload, timeout=60) as response:
1117
- if response.status == 200:
1118
- data = await response.json()
1119
- final_answer = data["choices"][0]["message"]["content"]
1120
- break
1121
- except Exception:
1122
- continue
1123
- if final_answer: break
1124
- await asyncio.sleep(2)
 
 
 
1125
 
 
 
 
1126
  try:
1127
  if proc_msg:
1128
  msg_id = getattr(proc_msg, 'message_id', None)
1129
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1130
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1131
  except Exception: pass
1132
 
1133
  if not final_answer:
@@ -1135,12 +1203,13 @@ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=Non
1135
  await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", False)
1136
  return
1137
 
1138
- history.append({"role": "model", "parts":[{"text": final_answer}]})
 
1139
  user_states[chat_id]["history"] = history
1140
 
1141
  try:
1142
  max_len = 1000
1143
- chunks =[]
1144
  temp_text = final_answer
1145
  while len(temp_text) > max_len:
1146
  split_idx = temp_text.rfind('\n', 0, max_len)
 
93
  return jy, jm, jd
94
 
95
  # ==============================================================================
96
+ # 🟢 پارت 4: دیتابیس SQLite (نسخه فوق‌سریع - فقط RAM برای پیام‌ها + پاکسازی هارد)
97
  # ==============================================================================
98
  import os
99
  import sqlite3
 
106
  BACKUP_JSON = "/data/users_db.json.bak"
107
 
108
  last_saved_state = {}
109
+ # حافظه کش فقط در RAM (با ری‌استارت اسپیس پاک می‌شود)
110
  recent_messages_dict = {}
111
  # قفل‌ها برای جلوگیری از تداخل رشته‌ها (Threads)
112
  db_lock = threading.Lock()
 
119
 
120
  conn = sqlite3.connect(DB_FILE, timeout=60.0)
121
  cursor = conn.cursor()
122
+
123
+ # 🚀 تنظیمات سرعت دیتابیس
124
  cursor.execute('PRAGMA journal_mode=WAL;')
125
  cursor.execute('PRAGMA synchronous=NORMAL;')
126
+
127
+ # 1️⃣ اطمینان از وجود و سلامت جدول کاربران (اطلاعات اصلی که نباید پاک شود)
128
  cursor.execute('CREATE TABLE IF NOT EXISTS users (chat_id TEXT PRIMARY KEY, user_data TEXT)')
129
+
130
+ # 2️⃣ حذف جدول شناسه‌های قدیمی پیام‌ها برای همیشه
131
+ cursor.execute('DROP TABLE IF EXISTS processed_messages')
132
  conn.commit()
133
+
134
+ # 3️⃣ آزادسازی فضای هارد دیسک و کاهش حجم فایل دیتابیس (حذف فیزیکی شناسه‌های قدیمی)
135
+ conn.execute('VACUUM')
136
+
137
  conn.close()
138
 
139
  if is_first_run:
140
  print("🚨 عملیات نجات آغاز شد...")
141
  restore_users_from_json()
 
142
 
143
  except Exception as e:
144
  print(f"❌ خطا در راه اندازی دیتابیس: {e}")
 
160
  except Exception as e:
161
  print(f"❌ خطا در بازیابی اعتبارها: {e}")
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  def load_db():
164
  global last_saved_state, recent_messages_dict
165
  init_sqlite_db()
 
169
  conn.execute('PRAGMA journal_mode=WAL;')
170
  cursor = conn.cursor()
171
 
172
+ # 🟢 فقط لود کردن اطلاعات کاربران (بدون دست زدن به شناسه‌های پیام)
173
  cursor.execute("SELECT chat_id, user_data FROM users")
174
  for row in cursor.fetchall():
175
  db_dict[row[0]] = json.loads(row[1])
176
 
 
 
 
 
 
177
  conn.close()
178
  last_saved_state = copy.deepcopy(db_dict)
179
+ print(f"🚀 دیتابیس آماده شد. تعداد کاربران: {len(db_dict)} | کش پیام‌ها پاکسازی شد.")
180
  return db_dict
181
  except Exception as e:
182
  print(f"⚠️ ارور در لود نهایی: {e}")
183
  return {}
184
 
185
+ # --- سیستم ذخیره سازی کاربران در پس‌زمینه ---
186
  def background_save_worker(changed_data):
187
  with db_lock:
188
  try:
 
197
 
198
  def save_db(db_data):
199
  global last_saved_state
200
+ changed = []
201
  for cid, data in db_data.items():
202
  if cid not in last_saved_state or last_saved_state[cid] != data:
203
  changed.append((str(cid), json.dumps(data, ensure_ascii=False)))
 
208
  for cid, _ in changed:
209
  last_saved_state[cid] = copy.deepcopy(db_data[cid])
210
 
 
211
  threading.Thread(target=background_save_worker, args=(changed,), daemon=True).start()
212
 
213
+ # --- سیستم ضد تکرار پیام کاملاً منتقل شده به RAM ---
214
  def is_message_processed(message_id):
215
+ # چک کردن داخل RAM در کسری از ثانیه
216
  return str(message_id) in recent_messages_dict
217
 
 
 
 
 
 
 
 
 
 
 
218
  def mark_message_processed(message_id):
219
  msg_id_str = str(message_id)
220
  with msg_cache_lock:
221
+ # ثبت فقط در RAM
222
  recent_messages_dict[msg_id_str] = True
223
+
224
+ # جلوگیری از پر شدن بیش از حد RAM (نگه داشتن فقط 15000 پیام آخر)
225
  if len(recent_messages_dict) > 15000:
226
  oldest_key = next(iter(recent_messages_dict))
227
  del recent_messages_dict[oldest_key]
 
 
 
228
 
229
  user_credits_db = load_db()
230
 
 
977
  if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
978
 
979
  # ==============================================================================
980
+ # 🟢 پارت 13: پردازش هوش مصنوعی متنی و تصویری جیمینای و هاگینگ‌فیس (ترکیب با Aya)
981
  # ==============================================================================
 
 
 
982
  async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
983
  str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
984
  creds = get_user_credits(str_chat_id)
985
  if creds["chat"] <= 0:
986
  return await send_with_keyboard(client, chat_id, "❌ اعتبار پیام‌های چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
987
 
 
 
988
  proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
989
+ history = user_states[chat_id].get("history", [])
990
+ new_parts = []
991
 
992
+ is_image = False
993
  has_non_image_file = False
994
 
995
  if prompt: new_parts.append({"text": prompt})
 
1014
 
1015
  new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
1016
 
1017
+ # اضافه کردن پیام جدید به تاریخچه مشترک ربات
1018
  if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
1019
  else: history.append({"role": "user", "parts": new_parts})
1020
 
1021
+ # 🔴 محدود کردن طول تاریخچه به ۲۰ پیام (۱۰ پیام کاربر + ۱۰ پیام ربات)
1022
+ if len(history) > 50:
1023
+ history = history[-50:]
1024
  if history[0]["role"] == "model": history = history[1:]
1025
 
1026
  final_answer = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1027
 
1028
+ # =========================================================================
1029
+ # 🔴 مسیر اول: اگر کاربر فایل یا عکس ارسال کرده باشد (استفاده از جیمینای)
1030
+ # =========================================================================
1031
+ if file_bytes is not None:
1032
+ if not GEMINI_KEYS:
1033
  try:
1034
  if proc_msg:
1035
  msg_id = getattr(proc_msg, 'message_id', None)
1036
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1037
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
1038
  except Exception: pass
1039
+ return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
1040
+
1041
+ for attempt in range(3):
1042
+ keys_to_try = get_next_gemini_keys(100)
1043
+ async with aiohttp.ClientSession() as session:
1044
+ for key in keys_to_try:
1045
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1046
+ payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
1047
+ try:
1048
+ async with session.post(url, json=payload, timeout=60) as response:
1049
+ if response.status == 200:
1050
+ data = await response.json()
1051
+ try:
1052
+ final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
1053
+ break
1054
+ except (KeyError, IndexError): continue
1055
+ except Exception: continue
1056
+ if final_answer: break
1057
+ await asyncio.sleep(2)
1058
+
1059
+ if not final_answer:
1060
+ if has_non_image_file:
1061
+ if history and history[-1]["role"] == "user": history.pop()
1062
+ try:
1063
+ if proc_msg:
1064
+ msg_id = getattr(proc_msg, 'message_id', None)
1065
+ if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1066
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
1067
+ except Exception: pass
1068
+ await send_with_keyboard(client, chat_id, "❌ متأسفانه سرور اصلی در حال حاضر شلوغ است و در این شرایط **فعلاً تنها امکان تحلیل تصاویر** توسط سرور جایگزین در دسترس است.", False)
1069
+ return
1070
+
1071
+ if HF_TOKENS:
1072
+ hf_messages = []
1073
+ for msg in history:
1074
+ role = "assistant" if msg["role"] == "model" else "user"
1075
+ content_parts = []
1076
+ for part in msg["parts"]:
1077
+ if "text" in part:
1078
+ content_parts.append({"type": "text", "text": part["text"]})
1079
+ elif "inlineData" in part:
1080
+ mime_t = part["inlineData"]["mimeType"]
1081
+ b64_d = part["inlineData"]["data"]
1082
+ if mime_t.startswith('image/'):
1083
+ content_parts.append({
1084
+ "type": "image_url",
1085
+ "image_url": {"url": f"data:{mime_t};base64,{b64_d}"}
1086
+ })
1087
+ if content_parts:
1088
+ hf_messages.append({"role": role, "content": content_parts})
1089
+
1090
+ for attempt in range(3):
1091
+ keys_to_try_hf = HF_TOKENS.copy()
1092
+ random.shuffle(keys_to_try_hf)
1093
+ async with aiohttp.ClientSession() as session:
1094
+ for hf_key in keys_to_try_hf:
1095
+ url = "https://router.huggingface.co/v1/chat/completions"
1096
+ headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1097
+ payload = {
1098
+ "model": "google/gemma-4-31B-it:novita",
1099
+ "messages": hf_messages,
1100
+ "max_tokens": 4096
1101
+ }
1102
+ try:
1103
+ async with session.post(url, headers=headers, json=payload, timeout=60) as response:
1104
+ if response.status == 200:
1105
+ data = await response.json()
1106
+ final_answer = data["choices"][0]["message"]["content"]
1107
+ break
1108
+ except Exception:
1109
+ continue
1110
+ if final_answer: break
1111
+ await asyncio.sleep(2)
1112
+
1113
+ # =========================================================================
1114
+ # 🟢 مسیر دوم: اگر فقط متن بود (استفاده از اسپیس Cohere Labs Aya Expanse)
1115
+ # =========================================================================
1116
+ else:
1117
+ # 🟢 تزریق شخصیت و دستورالعمل جدید به مدل
1118
+ system_rules = """تو یک دستیار با مزه از برنامه هوش مصنوعی آلفا هستی😊 و توسط هوش مصنوعی آلفا توسعه داده شدی.
1119
+ اینگونه می‌تونی خودت رو معرفی کنی، من یه هوش مصنوعیِ ساخته‌شده توسط تیم‌ تخصصی آلفا ام، و بر پایه مدل GPT-5.4 کار می‌کنم. یعنی یه نوع نرم‌افزار خیلی هوشمند که با کمک میلیون‌ها داده و آموزش‌های پیشرفته ساخته شده، تا بتونه بهت کمک کنه، سوالاتت رو جواب بده، یا حتی یه شوخی خنده‌دار برات بگه وقتی حال و هوات گرفته‌ست!
1120
+ در واقع، من نتیجه سال‌ها تحقیقات و تلاش‌های مهندس‌ها و پژوهشگرها هستم، تا جایی که می‌تونم بهترین کمک رو بهت بکنم. این دستورات های تو هستند و بصورت رندوم متفاوت جواب بده و تز شکلک های مناسب و جواب های جذاب استفاده کن."""
1121
+
1122
+ # 🟢 استخراج تاریخچه و تبدیل آن به متنی پیوسته جهت تزریق مستقیم به حافظه مدل (تضمین ۱۰۰٪ یادآوری)
1123
+ text_history = ""
1124
+ gradio_history = []
1125
+ temp_user_msg = ""
1126
+
1127
+ for msg in history[:-1]:
1128
+ text_content = "".join([p.get("text", "") for p in msg.get("parts", []) if "text" in p]).strip()
1129
+ if not text_content: continue
1130
 
1131
+ if msg["role"] == "user":
1132
+ temp_user_msg = text_content
1133
+ text_history += f"کاربر: {text_content}\n"
1134
+ elif msg["role"] == "model":
1135
+ text_history += f"آلفا: {text_content}\n"
1136
+ if temp_user_msg:
1137
+ gradio_history.append([temp_user_msg, text_content])
1138
+ temp_user_msg = ""
1139
+ else:
1140
+ gradio_history.append(["", text_content])
1141
+
1142
+ # ادغام دستورات، تاریخچه گذشته و پیام جدید به یک پرامپت قدرتمند
1143
+ if text_history:
1144
+ full_prompt = f"{system_rules}\n\n--- تاریخچه مکالمه تا این لحظه ---\n{text_history}\n--- پایان تاریخچه ---\n\nپیام جدید کاربر:\n{prompt}"
1145
+ else:
1146
+ full_prompt = f"{system_rules}\n\n---\nپیام جدید کاربر:\n{prompt}"
 
 
1147
 
1148
+ session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
1149
+ join_url = "https://coherelabs-aya-expanse.hf.space/gradio_api/queue/join"
1150
+ data_url = f"https://coherelabs-aya-expanse.hf.space/gradio_api/queue/data?session_hash={session_hash}"
1151
+
1152
+ # ساختار Payload دقیقاً منطبق با اسپیس
1153
+ payload = {
1154
+ "data": [
1155
+ full_prompt,
1156
+ gradio_history,
1157
+ None,
1158
+ None
1159
+ ],
1160
+ "event_data": None,
1161
+ "fn_index": 2,
1162
+ "session_hash": session_hash,
1163
+ "trigger_id": 37
1164
+ }
1165
+
1166
+ for attempt in range(3):
1167
+ try:
1168
  async with aiohttp.ClientSession() as session:
1169
+ async with session.post(join_url, json=payload, timeout=30) as resp:
1170
+ if resp.status == 200:
1171
+ async with session.get(data_url, timeout=120) as data_resp:
1172
+ async for line_bytes in data_resp.content:
1173
+ line = line_bytes.decode('utf-8').strip()
1174
+ if line.startswith("data: "):
1175
+ try:
1176
+ json_data = json.loads(line[6:])
1177
+ if json_data.get("msg") == "process_completed":
1178
+ if json_data.get("success"):
1179
+ output_data = json_data.get("output", {}).get("data", [])
1180
+ if output_data and len(output_data) > 0:
1181
+ result_hist = output_data[0]
1182
+ if isinstance(result_hist, list) and len(result_hist) > 0:
1183
+ final_answer = result_hist[-1][1]
1184
+ break
1185
+ except Exception: pass
1186
+ except Exception: pass
1187
+
1188
+ if final_answer: break
1189
+ await asyncio.sleep(2)
1190
 
1191
+ # =========================================================================
1192
+ # 🏁 پایان پردازش و ارسال نتیجه نهایی به کاربر
1193
+ # =========================================================================
1194
  try:
1195
  if proc_msg:
1196
  msg_id = getattr(proc_msg, 'message_id', None)
1197
  if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1198
+ if msg_id: await client.delete_messages(chat_id, [msg_id])
1199
  except Exception: pass
1200
 
1201
  if not final_answer:
 
1203
  await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", False)
1204
  return
1205
 
1206
+ # ذخیره پاسخ در تاریخچه چت کاربر
1207
+ history.append({"role": "model", "parts": [{"text": final_answer}]})
1208
  user_states[chat_id]["history"] = history
1209
 
1210
  try:
1211
  max_len = 1000
1212
+ chunks = []
1213
  temp_text = final_answer
1214
  while len(temp_text) > max_len:
1215
  split_idx = temp_text.rfind('\n', 0, max_len)