Update main.py
Browse files
main.py
CHANGED
|
@@ -93,7 +93,7 @@ def gregorian_to_jalali(gy, gm, gd):
|
|
| 93 |
return jy, jm, jd
|
| 94 |
|
| 95 |
# ==============================================================================
|
| 96 |
-
# 🟢 پارت 4: دیتابیس SQLite (نسخه فوقسریع
|
| 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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
| 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)} | پیامها
|
| 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 |
-
# --- سیستم
|
| 226 |
def is_message_processed(message_id):
|
| 227 |
-
# چک کردن داخل RAM
|
| 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 |
-
|
|
|
|
| 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 =
|
| 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 |
-
|
| 1050 |
-
|
|
|
|
| 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 |
-
|
| 1073 |
-
|
| 1074 |
-
|
|
|
|
|
|
|
| 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, "❌
|
| 1082 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1083 |
|
| 1084 |
-
|
| 1085 |
-
|
| 1086 |
-
|
| 1087 |
-
|
| 1088 |
-
|
| 1089 |
-
|
| 1090 |
-
|
| 1091 |
-
|
| 1092 |
-
|
| 1093 |
-
|
| 1094 |
-
|
| 1095 |
-
|
| 1096 |
-
|
| 1097 |
-
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
if content_parts:
|
| 1101 |
-
hf_messages.append({"role": role, "content": content_parts})
|
| 1102 |
|
| 1103 |
-
|
| 1104 |
-
|
| 1105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1106 |
async with aiohttp.ClientSession() as session:
|
| 1107 |
-
|
| 1108 |
-
|
| 1109 |
-
|
| 1110 |
-
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
| 1115 |
-
|
| 1116 |
-
|
| 1117 |
-
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
-
|
| 1121 |
-
|
| 1122 |
-
|
| 1123 |
-
|
| 1124 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
| 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)
|