Opera8 commited on
Commit
326db5f
·
verified ·
1 Parent(s): 1a1634e

Delete main (پاکسازی).py

Browse files
Files changed (1) hide show
  1. main (پاکسازی).py +0 -1883
main (پاکسازی).py DELETED
@@ -1,1883 +0,0 @@
1
- # ==============================================================================
2
- # 🟢 پارت 1: وارد کردن کتابخانه‌ها و ماژول‌ها (Imports)
3
- # ==============================================================================
4
- import os
5
- import time
6
- import threading
7
- import random
8
- import aiohttp
9
- import traceback
10
- import asyncio
11
- import base64
12
- import mimetypes
13
- import io
14
- import json
15
- import datetime
16
- import string
17
- import uuid
18
- import concurrent.futures
19
- import sqlite3 # 🟢 اضافه شده برای دیتابیس فوق‌سریع
20
- import copy # 🟢 اضافه شده برای سیستم تشخیص تغییرات دیتابیس
21
- from flask import Flask
22
- from rubpy.bot import BotClient, filters
23
-
24
- from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download
25
- from PIL import Image
26
- from pydub import AudioSegment
27
-
28
- # ==============================================================================
29
- # 🟢 پارت 2: تنظیمات سرورها، مدل‌های تغییر صدا و کلون صدا
30
- # ==============================================================================
31
- # --- تنظیمات آدرس سرورهای تغییر صدا ---
32
- VC_BASE_URL = "https://sada8888-sada.hf.space"
33
- LEGACY_BASE_URL = "https://ezmarynoori-rvc.hf.space"
34
-
35
- LEGACY_MODELS = {
36
- "1": {"name": "شادمهر", "url": "https://huggingface.co/amirmatrix/shadmehr/resolve/main/added_IVF722_Flat_nprobe_1_shadmehr_v2.zip?download=true", "gender": "male"},
37
- "2": {"name": "معین", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Moein.zip?download=true", "gender": "male"},
38
- "3": {"name": "بیلی آیلیش", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Billie.zip?download=true", "gender": "female"},
39
- "4": {"name": "محسن چاوشی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/chavoshi250.zip?download=true", "gender": "male"},
40
- "5": {"name": "سیاوش قمیشی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Ghomayshi250.zip?download=true", "gender": "male"},
41
- "6": {"name": "یاس", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Yas300.zip?download=true", "gender": "male"},
42
- "7": {"name": "عادل فردوسی‌پور", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Adel.zip?download=true", "gender": "male"},
43
- "8": {"name": "باب اسفنجی", "url": "https://huggingface.co/datasets/Hamed744/Ezmary/resolve/main/Bab_Asfanj300.zip?download=true", "gender": "male"}
44
- }
45
-
46
- STANDARD_MODELS = {
47
- "9": {"name": "علی سورنا", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D9%85%D8%AF%D9%84%20%D8%B5%D8%AF%D8%A7%DB%8C%20%D8%B3%D9%88%D8%B1%D9%86%D8%A7.mp3?download=true"},
48
- "10": {"name": "رونالدو", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D8%B1%D9%88%D9%86%D8%A7%D9%84%D8%AF%D9%88.wav?download=true"},
49
- "11": {"name": "مسی", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D8%B5%D8%AF%D8%A7%DB%8C-%D9%85%D8%B3%DB%8C.mp3?download=true"},
50
- "12": {"name": "مریم", "ref": "https://huggingface.co/datasets/Hamed744/mp3/resolve/main/%D8%B5%D8%AF%D8%A7%DB%8C%20%D8%AE%D8%A7%D9%86%D9%85.wav?download=true"}
51
- }
52
-
53
- # ==============================================================================
54
- # 🟢 پارت 3: متغیرهای ادمین، سیستم ضد اسپم و توابع تبدیل تاریخ
55
- # ==============================================================================
56
- # --- کد مدیریت ---
57
- ADMIN_CODE = "3011"
58
- BOT_GUID = None
59
-
60
- # =======================================================
61
- # سیستم ضد اسپم کاربر-محور
62
- # =======================================================
63
- user_message_times = {}
64
-
65
- def is_user_spamming(chat_id):
66
- now = time.time()
67
- times = user_message_times.get(chat_id,[])
68
- times =[t for t in times if now - t < 3.0]
69
- times.append(now)
70
- user_message_times[chat_id] = times
71
- if len(times) > 4:
72
- return True
73
- return False
74
-
75
- def gregorian_to_jalali(gy, gm, gd):
76
- g_d_m =[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
77
- gy2 = (gy + 1) if (gm > 2) else gy
78
- days = 355666 + (365 * gy) + ((gy2 + 3) // 4) - ((gy2 + 99) // 100) + ((gy2 + 399) // 400) + gd + g_d_m[gm - 1]
79
- jy = -1595 + (33 * (days // 12053))
80
- days %= 12053
81
- jy += 4 * (days // 1461)
82
- days %= 1461
83
- if days > 365:
84
- jy += (days - 1) // 365
85
- days = (days - 1) % 365
86
- if days < 186:
87
- jm = 1 + (days // 31)
88
- jd = 1 + (days % 31)
89
- else:
90
- jm = 7 + ((days - 186) // 30)
91
- jd = 1 + ((days - 186) % 30)
92
- return jy, jm, jd
93
-
94
- # ==============================================================================
95
- # 🟢 پارت 4: دیتابیس SQLite (نسخه نجات همه‌جانبه: اعتبارها + پیام‌های قدیمی)
96
- # ==============================================================================
97
- import os
98
- import sqlite3
99
- import json
100
- import copy
101
-
102
- # استفاده از نام جدید v3 برای شروع کاملاً پاک و بدون قفل
103
- DB_FILE = "/data/users_v3.db"
104
- CORRUPT_FILE = "/data/users_db.db" # فایل ۱۱.۷ مگابایتی شما
105
- BACKUP_JSON = "/data/users_db.json.bak" # فایل ۴.۷ مگابایتی اعتبارها
106
-
107
- last_saved_state = {}
108
-
109
- def init_sqlite_db():
110
- try:
111
- os.makedirs(os.path.dirname(DB_FILE), exist_ok=True)
112
-
113
- # اگر فایل v3 وجود ندارد، یعنی بار اول است و باید نجات را شروع کنیم
114
- is_first_run = not os.path.exists(DB_FILE)
115
-
116
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
117
- cursor = conn.cursor()
118
- cursor.execute('PRAGMA journal_mode=DELETE;') # امن‌ترین حالت برای شبکه
119
- cursor.execute('CREATE TABLE IF NOT EXISTS users (chat_id TEXT PRIMARY KEY, user_data TEXT)')
120
- cursor.execute('CREATE TABLE IF NOT EXISTS processed_messages (message_id TEXT PRIMARY KEY)')
121
- conn.commit()
122
- conn.close()
123
-
124
- if is_first_run:
125
- print("🚨 عملیات نجات آغاز شد...")
126
- # ۱. بازیابی اعتبارها از JSON (۱۰۰ درصد مطمئن)
127
- restore_users_from_json()
128
- # ۲. نجات شناسه‌های پیام از فایل ۱۱.۷ مگابایتی (تا جایی که راه بدهد)
129
- salvage_messages_from_corrupt_db()
130
-
131
- except Exception as e:
132
- print(f"❌ خطا در راه اندازی دیتابیس: {e}")
133
-
134
- def restore_users_from_json():
135
- if os.path.exists(BACKUP_JSON):
136
- print("📥 در حال بازیابی اعتبار کاربران از فایل پشتیبان...")
137
- try:
138
- with open(BACKUP_JSON, "r", encoding="utf-8") as f:
139
- data = json.load(f)
140
- if data:
141
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
142
- for cid, udata in data.items():
143
- conn.execute("INSERT OR REPLACE INTO users VALUES (?, ?)", (str(cid), json.dumps(udata)))
144
- conn.commit()
145
- conn.close()
146
- print(f"✅ اعتبار {len(data)} کاربر با موفقیت بازیابی شد.")
147
- except Exception as e:
148
- print(f"❌ خطا در بازیابی اعتبارها: {e}")
149
-
150
- def salvage_messages_from_corrupt_db():
151
- if os.path.exists(CORRUPT_FILE):
152
- print(f"🔍 در حال تلاش برای نجات شناسه‌های پیام از فایل {CORRUPT_FILE} ...")
153
- try:
154
- # وصل کردن فایل خراب به دیتابیس جدید
155
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
156
- conn.execute(f"ATTACH DATABASE '{CORRUPT_FILE}' AS old_db")
157
-
158
- # کپی کردن شناسه‌ها (با استفاده از INSERT OR IGNORE که اگر خراب بود رد شود)
159
- # این دستور تلاش می‌کند حتی اگر فایل Malformed باشد، ردیف‌های سالم را بردارد
160
- conn.execute("INSERT OR IGNORE INTO processed_messages SELECT message_id FROM old_db.processed_messages")
161
-
162
- conn.commit()
163
- conn.close()
164
- print("✅ شناسه‌های پیام قدیمی با موفقیت نجات یافتند و به دیتابیس جدید منتقل شدند.")
165
- except Exception as e:
166
- print(f"⚠️ هشدار: برخی پیام‌ها به دلیل خرابی شدید فایل اصلی قابل نجات نبودند، اما نگران نباشید، ربات دوباره آن‌ها را شناسایی می‌کند. ارور: {e}")
167
-
168
- def load_db():
169
- global last_saved_state
170
- init_sqlite_db()
171
- db_dict = {}
172
- try:
173
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
174
- cursor = conn.cursor()
175
- cursor.execute("SELECT chat_id, user_data FROM users")
176
- for row in cursor.fetchall():
177
- db_dict[row[0]] = json.loads(row[1])
178
- conn.close()
179
- last_saved_state = copy.deepcopy(db_dict)
180
- print(f"🚀 دیتابیس نهایی آماده شد. تعداد کاربران: {len(db_dict)}")
181
- return db_dict
182
- except Exception as e:
183
- print(f"⚠️ ارور در لود نهایی: {e}")
184
- return {}
185
-
186
- def save_db(db_data):
187
- global last_saved_state
188
- try:
189
- changed = []
190
- for cid, data in db_data.items():
191
- if cid not in last_saved_state or last_saved_state[cid] != data:
192
- changed.append((str(cid), json.dumps(data, ensure_ascii=False)))
193
- if not changed: return
194
- conn = sqlite3.connect(DB_FILE, timeout=60.0)
195
- conn.execute('PRAGMA journal_mode=DELETE;')
196
- conn.executemany("INSERT OR REPLACE INTO users (chat_id, user_data) VALUES (?, ?)", changed)
197
- conn.commit()
198
- conn.close()
199
- for cid, _ in changed:
200
- last_saved_state[cid] = copy.deepcopy(db_data[cid])
201
- except Exception as e:
202
- print(f"❌ خطا در ذخیره: {e}")
203
-
204
- def is_message_processed(message_id):
205
- try:
206
- conn = sqlite3.connect(DB_FILE, timeout=30.0)
207
- res = conn.execute("SELECT 1 FROM processed_messages WHERE message_id = ?", (str(message_id),)).fetchone()
208
- conn.close()
209
- return res is not None
210
- except: return False
211
-
212
- def mark_message_processed(message_id):
213
- try:
214
- conn = sqlite3.connect(DB_FILE, timeout=30.0)
215
- conn.execute("INSERT OR IGNORE INTO processed_messages VALUES (?)", (str(message_id),))
216
- conn.commit()
217
- conn.close()
218
- except: pass
219
-
220
- user_credits_db = load_db()
221
-
222
-
223
- # ==============================================================================
224
- # 🟢 پارت 5: توابع کد معرف، مدیریت سهمیه حساب کاربری و تبدیل اعداد
225
- # ==============================================================================
226
- def get_or_create_referral_code(chat_id):
227
- user_data = user_credits_db[chat_id]
228
- if not user_data.get("referral_code"):
229
- while True:
230
- new_code = ''.join(random.choices(string.digits, k=8))
231
- exists = any(isinstance(u, dict) and u.get("referral_code") == new_code for u in user_credits_db.values())
232
- if not exists:
233
- user_data["referral_code"] = new_code
234
- save_db(user_credits_db)
235
- break
236
- return user_data["referral_code"]
237
-
238
- def find_user_by_referral_code(code):
239
- code = code.strip()
240
- for uid, data in user_credits_db.items():
241
- if isinstance(data, dict) and data.get("referral_code", "") == code:
242
- return uid
243
- return None
244
-
245
- def get_user_credits(chat_id):
246
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
247
- today_str = datetime.date.today().isoformat()
248
-
249
- if str_chat_id not in user_credits_db or not isinstance(user_credits_db[str_chat_id], dict):
250
- user_credits_db[str_chat_id] = {
251
- "is_premium": False,
252
- "expire_date": None,
253
- "last_reset": "",
254
- "chat": 10,
255
- "image": 5,
256
- "edit_image": 1,
257
- "podcast": 2,
258
- "tts": 5,
259
- "file": 1,
260
- "stt": 5,
261
- "voice_conv": 3,
262
- "voice_clone": 1,
263
- "last_msg_id": 0,
264
- "has_joined": False,
265
- "invited_count": 0,
266
- "used_referral": False,
267
- "referral_code": ""
268
- }
269
- save_db(user_credits_db)
270
-
271
- user_data = user_credits_db[str_chat_id]
272
-
273
- if "voice_conv" not in user_data: user_data["voice_conv"] = 3
274
- if "voice_clone" not in user_data: user_data["voice_clone"] = 1
275
- if "last_msg_id" not in user_data: user_data["last_msg_id"] = 0
276
-
277
- is_premium = user_data.get("is_premium", False)
278
-
279
- if is_premium and user_data.get("expire_date"):
280
- try:
281
- expire_date = datetime.datetime.fromisoformat(user_data["expire_date"])
282
- if datetime.datetime.now() > expire_date:
283
- user_data["is_premium"] = False
284
- user_data["expire_date"] = None
285
- is_premium = False
286
- except Exception:
287
- pass
288
-
289
- if not is_premium:
290
- if user_data.get("last_reset") != today_str:
291
- user_data["last_reset"] = today_str
292
- user_data["chat"] = 10
293
- user_data["image"] = 5
294
- user_data["edit_image"] = 1
295
- user_data["podcast"] = 2
296
- user_data["tts"] = 5
297
- user_data["file"] = 1
298
- user_data["stt"] = 5
299
- user_data["voice_conv"] = 3
300
- user_data["voice_clone"] = 1
301
- save_db(user_credits_db)
302
-
303
- return user_data
304
-
305
- def to_english_digits(text):
306
- if not text: return text
307
- persian_digits = '۰۱۲۳۴۵۶۷۸۹'
308
- arabic_digits = '٠١٢٣٤٥٦٧٨٩'
309
- english_digits = '0123456789'
310
- translation_table = str.maketrans(persian_digits + arabic_digits, english_digits * 2)
311
- return str(text).translate(translation_table)
312
-
313
- # ==============================================================================
314
- # 🟢 پارت 6: تنظیمات وب‌سرور (Flask) و توابع کمکی فایل‌ها
315
- # ==============================================================================
316
- # --- تنظیمات وب سرور ---
317
- app = Flask(__name__)
318
-
319
- @app.route('/')
320
- def home():
321
- return "ربات یکپارچه آلفا (نسخه پرو + مدیریت اشتراک نامحدود + دعوت دوستان + سیستم تغییر صدا) روشن است! 🚀"
322
-
323
- def run_flask():
324
- app.run(host="0.0.0.0", port=7860, threaded=True)
325
-
326
- # --- توابع کمکی ---
327
- def sync_save_image(image, file_name):
328
- rgb_im = image.convert('RGB')
329
- rgb_im.save(file_name, format="JPEG", quality=100)
330
-
331
- def sync_write_file(file_name, data):
332
- with open(file_name, "wb") as f:
333
- f.write(data)
334
-
335
- def sync_read_file(file_name):
336
- with open(file_name, 'rb') as f:
337
- return f.read()
338
-
339
- def sync_combine_audio(current_audio, new_bytes):
340
- audio_segment = AudioSegment.from_file(io.BytesIO(new_bytes))
341
- return current_audio + audio_segment
342
-
343
- def sync_export_audio(audio_obj, file_name):
344
- audio_obj.export(file_name, format="mp3")
345
-
346
- # ==============================================================================
347
- # 🟢 پارت 7: کیبوردها (دکمه‌های شیشه‌ای / منوها)
348
- # ==============================================================================
349
- # --- ساختار کیبورد ---
350
- MAIN_KEYPAD_DICT = {
351
- "rows":[
352
- {
353
- "buttons":[
354
- {"id": "chat_btn", "type": "Simple", "button_text": "چت با هوش مصنوعی 🤖"}
355
- ]
356
- },
357
- {
358
- "buttons":[
359
- {"id": "img_btn", "type": "Simple", "button_text": "ساخت تصاویر🎨"},
360
- {"id": "edit_img_btn", "type": "Simple", "button_text": "ویرایش تصاویر 🪄"}
361
- ]
362
- },
363
- {
364
- "buttons":[
365
- {"id": "podcast_btn", "type": "Simple", "button_text": "ساخت پادکست 🎙️"},
366
- {"id": "tts_btn", "type": "Simple", "button_text": "تبدیل متن به صدا🗣️"}
367
- ]
368
- },
369
- {
370
- "buttons":[
371
- {"id": "vc_btn", "type": "Simple", "button_text": "تغییر صدا 🎙️"},
372
- {"id": "clone_btn", "type": "Simple", "button_text": "کلون کردن صدا 👤"}
373
- ]
374
- },
375
- {
376
- "buttons":[
377
- {"id": "stt_btn", "type": "Simple", "button_text": "فایل صوتی به متن 📝"},
378
- {"id": "file_btn", "type": "Simple", "button_text": "تحلیل فایل 📁"}
379
- ]
380
- },
381
- {
382
- "buttons":[
383
- {"id": "create_file_btn", "type": "Simple", "button_text": "ساخت فایل 📄"}
384
- ]
385
- },
386
- {
387
- "buttons":[
388
- {"id": "account_btn", "type": "Simple", "button_text": "حساب کاربری 👤"},
389
- {"id": "buy_btn", "type": "Simple", "button_text": "خرید اشتراک 💎"}
390
- ]
391
- },
392
- {
393
- "buttons":[
394
- {"id": "invite_btn", "type": "Simple", "button_text": "دعوت دوستان 🎁"},
395
- {"id": "referral_btn", "type": "Simple", "button_text": "ثبت کد هدیه 🎫"}
396
- ]
397
- },
398
- {
399
- "buttons":[
400
- {"id": "transfer_btn", "type": "Simple", "button_text": "انتقال اکانت از برنامه به ربات"}
401
- ]
402
- },
403
- {
404
- "buttons":[
405
- {"id": "cancel_btn", "type": "Simple", "button_text": "برگشت♻️"}
406
- ]
407
- }
408
- ],
409
- "resize_keyboard": True
410
- }
411
-
412
- CHANNEL_USERNAME = "aialpha"
413
- CHANNEL_GUID = None
414
-
415
- JOIN_KEYPAD_DICT = {
416
- "rows":[
417
- {
418
- "buttons":[
419
- {"id": "check_join_btn", "type": "Simple", "button_text": "✅ عضو شدم"}
420
- ]
421
- }
422
- ],
423
- "resize_keyboard": True
424
- }
425
-
426
- # ==============================================================================
427
- # 🟢 پارت 8: تابع بررسی عضویت کانال، ارسال کیبورد و توکن روبیکا
428
- # ==============================================================================
429
- async def check_channel_membership(client, user_id):
430
- global CHANNEL_GUID
431
- if str(user_id) == str(BOT_GUID): return True
432
-
433
- try:
434
- if not CHANNEL_GUID:
435
- res = await client.get_object_by_username(CHANNEL_USERNAME)
436
- if isinstance(res, dict):
437
- if 'channel' in res and 'channel_guid' in res['channel']:
438
- CHANNEL_GUID = res['channel']['channel_guid']
439
- elif 'data' in res and 'channel' in res['data']:
440
- CHANNEL_GUID = res['data']['channel']['channel_guid']
441
- elif 'exist' in res and 'chat' in res['exist']:
442
- CHANNEL_GUID = res['exist']['chat']['object_guid']
443
- else:
444
- if hasattr(res, 'channel'):
445
- CHANNEL_GUID = getattr(res.channel, 'channel_guid', None)
446
- elif hasattr(res, 'data') and hasattr(res.data, 'channel'):
447
- CHANNEL_GUID = getattr(res.data.channel, 'channel_guid', None)
448
- elif hasattr(res, 'exist') and hasattr(res.exist, 'chat'):
449
- CHANNEL_GUID = getattr(res.exist.chat, 'object_guid', None)
450
-
451
- if not CHANNEL_GUID: return True
452
-
453
- payload = {"channel_guid": CHANNEL_GUID, "member_guid": user_id}
454
- res = await client._make_request("getChannelParticipant", payload)
455
-
456
- if isinstance(res, dict) and res.get("status") == "OK":
457
- data = res.get("data", {})
458
- if data and "participant" in data: return True
459
- elif hasattr(res, 'status') and getattr(res, 'status') == "OK":
460
- return True
461
- return False
462
- except Exception: return False
463
-
464
- async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
465
- try:
466
- if not use_keyboard: return await client.send_message(chat_id, text)
467
- payload = {"chat_id": chat_id, "text": text, "chat_keypad_type": "New", "chat_keypad": MAIN_KEYPAD_DICT}
468
- return await client._make_request("sendMessage", payload)
469
- except Exception:
470
- try: return await client.send_message(chat_id, text)
471
- except Exception: return None
472
-
473
- bot_token = os.environ.get("RUBIKA_AUTH", "").strip()
474
-
475
- # ==============================================================================
476
- # 🟢 پارت 9: دانلودر قدرتمند و تابع ضد قطعی روبیکا
477
- # ==============================================================================
478
- # ==================================================================
479
- # تابع دانلود ضد بمب اتم (پافشاری ۳۵ بار)
480
- # ==================================================================
481
- async def helper_download_file(client, msg_obj):
482
- errors =[]
483
- file_obj = None
484
- file_id = None
485
-
486
- for attr in['file', 'file_inline', 'photo', 'voice', 'audio', 'document', 'video']:
487
- val = getattr(msg_obj, attr, None)
488
- if val:
489
- file_obj = val
490
- if hasattr(val, 'file_id'): file_id = val.file_id
491
- elif isinstance(val, dict) and 'file_id' in val: file_id = val['file_id']
492
- break
493
-
494
- if not file_obj and hasattr(msg_obj, "file_id"):
495
- file_id = msg_obj.file_id
496
- file_obj = msg_obj
497
-
498
- if not file_id: raise Exception("خطا: هیچ فایلی در پیام یافت نشد.")
499
-
500
- temp_name = f"temp_dl_{uuid.uuid4().hex}.tmp"
501
-
502
- for attempt in range(20):
503
- try:
504
- url_get_file = f"https://botapi.rubika.ir/v3/{bot_token}/getFile"
505
- payload = {"file_id": str(file_id)}
506
- headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
507
-
508
- async with aiohttp.ClientSession() as session:
509
- async with session.post(url_get_file, json=payload, headers=headers, timeout=30) as resp:
510
- if resp.status == 200:
511
- res_data = await resp.json()
512
- if res_data.get("status") == "OK" or res_data.get("status_det") == "OK":
513
- download_url = res_data.get("data", {}).get("download_url") or res_data.get("data", {}).get("file_url")
514
- if download_url:
515
- for dl_attempt in range(3):
516
- try:
517
- async with session.get(download_url, headers=headers, timeout=60) as dl_resp:
518
- if dl_resp.status == 200:
519
- data = await dl_resp.read()
520
- if data and len(data) > 0: return data
521
- else: errors.append(f"DL HTTP {dl_resp.status}")
522
- await asyncio.sleep(2)
523
- except Exception as dl_err:
524
- errors.append(f"DL Error: {str(dl_err)[:30]}")
525
- await asyncio.sleep(2)
526
- else: errors.append("No download URL in response.")
527
- else: errors.append(f"API Not OK: {res_data.get('status')}")
528
- elif resp.status in [502, 503, 500]:
529
- errors.append(f"GetFile HTTP {resp.status}")
530
- await asyncio.sleep(3.5)
531
- continue
532
- else:
533
- errors.append(f"GetFile HTTP {resp.status}")
534
- await asyncio.sleep(2)
535
- except Exception as e:
536
- errors.append(f"API Error: {str(e)[:50]}")
537
- await asyncio.sleep(2)
538
-
539
- if file_obj:
540
- for attempt in range(10):
541
- try:
542
- if hasattr(client, "download"):
543
- result = await client.download(file_obj, save_as=temp_name)
544
- if isinstance(result, bytes) and len(result) > 0: return result
545
- if os.path.exists(temp_name):
546
- data = await asyncio.to_thread(sync_read_file, temp_name)
547
- os.remove(temp_name)
548
- if data and len(data) > 0: return data
549
- except Exception as e:
550
- errors.append(f"Rubpy Obj Error: {str(e)[:50]}")
551
- await asyncio.sleep(3)
552
-
553
- for attempt in range(5):
554
- try:
555
- if hasattr(client, "download_file"):
556
- await client.download_file(file_id, file_name=temp_name)
557
- if os.path.exists(temp_name):
558
- data = await asyncio.to_thread(sync_read_file, temp_name)
559
- os.remove(temp_name)
560
- if data and len(data) > 0: return data
561
- except Exception as e:
562
- errors.append(f"Rubpy FileId Error: {str(e)[:50]}")
563
- await asyncio.sleep(3)
564
-
565
- raise Exception(f"سرورهای دانلود روبیکا پس از ۳۵ بار تلاش پاسخ ندادند!\nلاگ خطاها: {str(errors[-5:])}")
566
-
567
- async def helper_download_url_to_bytes(url):
568
- async with aiohttp.ClientSession() as session:
569
- for _ in range(3):
570
- try:
571
- async with session.get(url, timeout=30) as resp:
572
- if resp.status == 200:
573
- return await resp.read()
574
- except Exception:
575
- await asyncio.sleep(2)
576
- return None
577
-
578
- # ==============================================================================
579
- # 🟢 پارت 10: سیستم چرخش کلیدهای جیمینای و تنظیم توکن‌های هاگینگ فیس
580
- # ==============================================================================
581
- # ==================================================================
582
- # توکن‌ها و کلیدها
583
- # ==================================================================
584
- GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "")
585
- GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "")
586
-
587
- _raw_keys =[]
588
- if GEMINI_KEYS_STR1: _raw_keys.extend(GEMINI_KEYS_STR1.split(","))
589
- if GEMINI_KEYS_STR2: _raw_keys.extend(GEMINI_KEYS_STR2.split(","))
590
-
591
- GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()]))
592
- print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.")
593
-
594
- current_gemini_key_index = 0
595
- gemini_key_lock = threading.Lock()
596
-
597
- def get_next_gemini_keys(count=100):
598
- global current_gemini_key_index
599
- with gemini_key_lock:
600
- total_keys = len(GEMINI_KEYS)
601
- if total_keys == 0: return[]
602
- actual_count = min(count, total_keys)
603
- selected_keys =[]
604
- for _ in range(actual_count):
605
- selected_keys.append(GEMINI_KEYS[current_gemini_key_index])
606
- current_gemini_key_index = (current_gemini_key_index + 1) % total_keys
607
- return selected_keys
608
-
609
- HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
610
- HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
611
-
612
- # ==============================================================================
613
- # 🟢 پارت 11: آپلودر قدرتمند و تابع ارسال فایل ضد خطا (نسخه نهایی ضد بمب اتم 🚀)
614
- # ==============================================================================
615
- async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
616
- abs_path = os.path.abspath(file_name)
617
- error_logs = []
618
-
619
- api_file_type = "Image" if file_type in["photo", "Image", "image"] else "Voice" if file_type in ["voice", "Voice", "audio"] else file_type
620
-
621
- # روبیکا فرمت‌های خاصی را قبول می‌کند.
622
- if api_file_type == "Voice" and not abs_path.lower().endswith('.ogg'):
623
- api_file_type = "Music"
624
- if api_file_type == "File" and abs_path.lower().endswith('.mp3'):
625
- api_file_type = "Music"
626
-
627
- # --- فاز اول (فوق سریع): استفاده از متدهای اختصاصی rubpy ---
628
- for attempt in range(10):
629
- try:
630
- sent_success = False
631
-
632
- # تلاش برای ارسال عکس
633
- if api_file_type == "Image" and hasattr(client, "send_photo"):
634
- try:
635
- await client.send_photo(chat_id, photo=abs_path, caption=caption)
636
- sent_success = True
637
- except TypeError:
638
- await client.send_photo(chat_id, abs_path, caption=caption)
639
- sent_success = True
640
-
641
- # تلاش برای ارسال ویس
642
- elif api_file_type == "Voice" and hasattr(client, "send_voice"):
643
- try:
644
- await client.send_voice(chat_id, abs_path, caption=caption)
645
- sent_success = True
646
- except TypeError:
647
- await client.send_voice(chat_id, file=abs_path, caption=caption)
648
- sent_success = True
649
-
650
- # تلاش برای ارسال موزیک
651
- elif api_file_type == "Music" and hasattr(client, "send_music"):
652
- try:
653
- await client.send_music(chat_id, abs_path, caption=caption)
654
- sent_success = True
655
- except TypeError:
656
- await client.send_music(chat_id, music=abs_path, caption=caption)
657
- sent_success = True
658
-
659
- # *** سیستم ضد بمب اتم فاز 1 ***
660
- # اگر هیچکدام از متدهای بالا وجود نداشت یا به هر دلیلی ارسال نشد، حتما به عنوان فایل (سند) بفرست تا معطل نشود
661
- if not sent_success:
662
- if hasattr(client, "send_document"):
663
- try:
664
- await client.send_document(chat_id, document=abs_path, caption=caption)
665
- sent_success = True
666
- except TypeError:
667
- await client.send_document(chat_id, abs_path, caption=caption)
668
- sent_success = True
669
- elif hasattr(client, "send_file"):
670
- try:
671
- await client.send_file(chat_id, file=abs_path)
672
- except TypeError:
673
- await client.send_file(chat_id, abs_path)
674
- if caption:
675
- await send_with_keyboard(client, chat_id, caption, True)
676
- sent_success = True
677
-
678
- if sent_success:
679
- return True
680
-
681
- except Exception as e:
682
- err_msg = str(e)[:150]
683
- error_logs.append(f"Rubpy Send Error: {err_msg}")
684
-
685
- if "502" in err_msg or "timeout" in err_msg.lower() or "time" in err_msg.lower():
686
- await asyncio.sleep(4)
687
- else:
688
- await asyncio.sleep(2)
689
-
690
- # --- فاز دوم (سنگر آخر): آپلود دستی (Raw HTTP) در صورت مسدودی کامل روب‌پای ---
691
- for attempt in range(15):
692
- try:
693
- url_request = f"https://botapi.rubika.ir/v3/{bot_token}/requestSendFile"
694
- url_send = f"https://botapi.rubika.ir/v3/{bot_token}/sendFile"
695
-
696
- async with aiohttp.ClientSession() as session:
697
- async with session.post(url_request, json={"type": api_file_type}, timeout=30) as resp:
698
- if resp.status != 200:
699
- error_logs.append(f"Request HTTP {resp.status}")
700
- await asyncio.sleep(2)
701
- continue
702
-
703
- req_data = await resp.json()
704
- if req_data.get("status") == "OK":
705
- upload_url = req_data.get("data", {}).get("upload_url")
706
- if upload_url:
707
- with open(abs_path, "rb") as f:
708
- form = aiohttp.FormData()
709
- form.add_field('file', f, filename=os.path.basename(abs_path))
710
- async with session.post(upload_url, data=form, timeout=300) as up_resp:
711
- if up_resp.status != 200:
712
- error_logs.append(f"Upload HTTP {up_resp.status}")
713
- if up_resp.status in[502, 503, 500]:
714
- await asyncio.sleep(3)
715
- else:
716
- await asyncio.sleep(1.5)
717
- continue
718
-
719
- try:
720
- up_data = await up_resp.json()
721
- except Exception as json_err:
722
- error_logs.append(f"JSON Decode Error: {json_err}")
723
- await asyncio.sleep(2)
724
- continue
725
-
726
- final_file_id = None
727
-
728
- # *** سیستم ضد بمب اتم فاز 2 ***
729
- # دور زدن ارور روبیکا: اگر روبیکا به فرمت فایل گیر داد، سریعاً نوع را به File تغییر بده تا بدون بررسی فرمت آپلود کند!
730
- if up_data.get("status") == "INVALID_INPUT" and "format" in str(up_data).lower():
731
- api_file_type = "File"
732
- error_logs.append(f"Format Blocked! Downgrading type to File.")
733
- await asyncio.sleep(1)
734
- continue
735
-
736
- if up_data.get("status") == "OK" or up_data.get("status_det") == "OK":
737
- if "data" in up_data and isinstance(up_data["data"], dict):
738
- final_file_id = up_data["data"].get("file_id") or up_data["data"].get("id")
739
- elif "file_id" in up_data:
740
- final_file_id = up_data.get("file_id")
741
-
742
- if final_file_id:
743
- send_payload = {
744
- "chat_id": str(chat_id),
745
- "file_id": str(final_file_id),
746
- "text": caption,
747
- "chat_keypad_type": "New",
748
- "chat_keypad": MAIN_KEYPAD_DICT
749
- }
750
- async with session.post(url_send, json=send_payload, timeout=30) as send_resp:
751
- if send_resp.status != 200:
752
- error_logs.append(f"Send HTTP {send_resp.status}")
753
- await asyncio.sleep(2)
754
- continue
755
-
756
- s_data = await send_resp.json()
757
- if s_data.get("status") == "OK": return True
758
- else: error_logs.append(f"SendFile API Error: {s_data}")
759
- else:
760
- if up_data.get("status") == "INVALID_INPUT" and api_file_type in ["Voice", "Music"]:
761
- api_file_type = "File" # دور زدن گیر دادن روبیکا
762
- error_logs.append(f"Upload API Error: {up_data}")
763
- else: error_logs.append(f"Missing upload_url in Response: {req_data}")
764
- else: error_logs.append(f"Request API Error: {req_data}")
765
- except Exception as e:
766
- error_logs.append(f"Raw HTTP Error: {str(e)[:100]}")
767
- await asyncio.sleep(2.5)
768
-
769
- return "\n".join(error_logs[-6:])
770
-
771
- # ==============================================================================
772
- # 🟢 پارت 12: توابع تغییر صدا و لیست گویندگان
773
- # ==============================================================================
774
- # ==================================================================
775
- # لیست‌های اولیه ربات
776
- # ==================================================================
777
- WORKER_URLS =["https://opera8-ttspro.hf.space/generate"]
778
-
779
- SPEAKERS = {
780
- "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
781
- "4": ("آرمان (مرد)", "Zubenelgenubi"), "5": ("مهسا (زن)", "Vindemiatrix"), "6": ("دانا (مرد)", "Rasalgethi"),
782
- "7": ("سامان (مرد)", "Sadachbia"), "8": ("آرش (مرد)", "Sadaltager"), "9": ("شبنم (زن)", "Sulafat"),
783
- "10": ("سحر (زن)", "Laomedeia"), "11": ("مریم (زن)", "Achernar"), "12": ("بهرام (مرد)", "Alnilam"),
784
- "13": ("نیکان (مرد)", "Schedar"), "14": ("فرناز (زن)", "Gacrux"), "15": ("سارا (زن)", "Pulcherrima"),
785
- "16": ("مانی (مرد)", "Umbriel"), "17": ("آرتین (مرد)", "Algieba"), "18": ("دلنواز (زن)", "Despina"),
786
- "19": ("روژان (زن)", "Erinome"), "20": ("امید (مرد)", "Algenib"), "21": ("بردیا (مرد)", "Orus"),
787
- "22": ("ترانه (زن)", "Aoede"), "23": ("نیکو (زن)", "Callirrhoe"), "24": ("هستی (زن)", "Autonoe"),
788
- "25": ("کامیار (مرد)", "Enceladus"), "26": ("کیانوش (مرد)", "Iapetus"), "27": ("پویا (مرد)", "Puck"),
789
- "28": ("مهتاب (زن)", "Kore"), "29": ("سام (مرد)", "Fenrir"), "30": ("لیدا (زن)", "Leda")
790
- }
791
-
792
- user_states = {}
793
-
794
- # ==================================================================
795
- # توابع تغییر صدا و کلون کردن
796
- # ==================================================================
797
- async def process_standard_vc_job(client, chat_id, src_bytes, ref_bytes, job_type_name, credit_type):
798
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
799
- creds = get_user_credits(str_chat_id)
800
-
801
- proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {job_type_name})", False)
802
-
803
- async with aiohttp.ClientSession() as session:
804
- form = aiohttp.FormData()
805
- form.add_field('source_audio', src_bytes, filename='src.wav', content_type='audio/wav')
806
- form.add_field('ref_audio', ref_bytes, filename='ref.wav', content_type='audio/wav')
807
-
808
- try:
809
- async with session.post(f"{VC_BASE_URL}/upload", data=form, timeout=43200) as resp:
810
- if resp.status != 200:
811
- return await send_with_keyboard(client, chat_id, f"❌ خطا در ارسال فایل‌ها (کد {resp.status})", True)
812
- data = await resp.json()
813
- job_id = data.get("job_id")
814
- total_chunks = data.get("total_chunks", 1)
815
- chunks = data.get("chunks",[])
816
- except Exception as e:
817
- return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور:\n{str(e)[:100]}", True)
818
-
819
- await send_with_keyboard(client, chat_id, "✅ فایل‌ها ارسال شد. در حال پردازش و تغییر صدا...\n(لطفا چند دقیقه صبور باشید)", False)
820
-
821
- final_filename = None
822
- for _ in range(10000):
823
- await asyncio.sleep(4)
824
- payload_check = {"job_id": job_id, "total_chunks": total_chunks, "chunks": chunks}
825
- try:
826
- async with session.post(f"{VC_BASE_URL}/check_status", json=payload_check, timeout=20) as c_resp:
827
- if c_resp.status == 200:
828
- c_data = await c_resp.json()
829
- if c_data.get("status") == "completed":
830
- final_filename = c_data.get("filename")
831
- break
832
- elif c_data.get("status") in ["failed", "error"]:
833
- return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش صدا.", True)
834
- except Exception:
835
- pass
836
-
837
- if not final_filename:
838
- return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True)
839
-
840
- download_url = f"{VC_BASE_URL}/download/{final_filename}"
841
- await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
842
- try:
843
- async with session.get(download_url, timeout=43200) as d_resp:
844
- if d_resp.status == 200:
845
- result_bytes = await d_resp.read()
846
- else:
847
- return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
848
- except Exception:
849
- return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی.", True)
850
-
851
- file_name_mp3 = f"vc_standard_{uuid.uuid4().hex[:6]}.mp3"
852
- await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
853
-
854
- upload_result = False
855
- for up_att in range(3):
856
- res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ {job_type_name} شما آماده است!")
857
- if res is True:
858
- upload_result = True
859
- break
860
- await asyncio.sleep(4)
861
-
862
- if upload_result is True:
863
- if not creds.get("is_premium"):
864
- user_credits_db[str_chat_id][credit_type] -= 1
865
- save_db(user_credits_db)
866
- else:
867
- await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال در روبیکا فراهم نشد.", True)
868
-
869
- if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
870
-
871
- async def process_legacy_vc_job(client, chat_id, src_bytes, model_url, pitch, model_name):
872
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
873
- creds = get_user_credits(str_chat_id)
874
-
875
- proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال آماده‌سازی فایل‌ها...\n(مدل: {model_name})", False)
876
-
877
- async with aiohttp.ClientSession() as session:
878
- form = aiohttp.FormData()
879
- form.add_field('audio_file', src_bytes, filename='input.wav', content_type='audio/wav')
880
- form.add_field('model_url', model_url)
881
- form.add_field('pitch', str(pitch))
882
- form.add_field('algo', 'rmvpe+')
883
- form.add_field('index_inf', '0.75')
884
- form.add_field('res_filter', '3')
885
- form.add_field('env_ratio', '0.25')
886
- form.add_field('protect', '0.33')
887
- form.add_field('denoise', 'false')
888
- form.add_field('reverb', 'false')
889
-
890
- try:
891
- async with session.post(f"{LEGACY_BASE_URL}/upload", data=form, timeout=43200) as resp:
892
- if resp.status != 200:
893
- return await send_with_keyboard(client, chat_id, f"❌ خطا در ارسال فایل‌ها (کد {resp.status})", True)
894
- data = await resp.json()
895
- job_id = data.get("job_id")
896
- except Exception as e:
897
- return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور:\n{str(e)[:100]}", True)
898
-
899
- await send_with_keyboard(client, chat_id, "✅ فایل ارسال شد. در حال پردازش و تغییر صدای شما...\n(لطفا چند دقیقه صبور باشید)", False)
900
-
901
- final_filename = None
902
- for _ in range(10000):
903
- await asyncio.sleep(5)
904
- try:
905
- async with session.get(f"{LEGACY_BASE_URL}/status/{job_id}", timeout=20) as c_resp:
906
- if c_resp.status == 200:
907
- c_data = await c_resp.json()
908
- if c_data.get("status") == "completed":
909
- final_filename = c_data.get("filename")
910
- break
911
- elif c_data.get("status") in["failed", "error", "not_found"]:
912
- return await send_with_keyboard(client, chat_id, "❌ خطای سرور در حین پردازش.", True)
913
- except Exception:
914
- pass
915
-
916
- if not final_filename:
917
- return await send_with_keyboard(client, chat_id, "❌ پردازش بیش از حد طول کشید و متوقف شد.", True)
918
-
919
- download_url = f"{LEGACY_BASE_URL}/download/{final_filename}"
920
- await send_with_keyboard(client, chat_id, "📥 پردازش تمام شد! در حال دانلود نتیجه...", False)
921
- try:
922
- async with session.get(download_url, timeout=43200) as d_resp:
923
- if d_resp.status == 200:
924
- result_bytes = await d_resp.read()
925
- else:
926
- return await send_with_keyboard(client, chat_id, "❌ خطا در دریافت فایل نهایی از سرور.", True)
927
- except Exception:
928
- return await send_with_keyboard(client, chat_id, "❌ خطا در اتصال هنگام دانلود خروجی.", True)
929
-
930
- file_name_mp3 = f"vc_legacy_{uuid.uuid4().hex[:6]}.mp3"
931
- await asyncio.to_thread(sync_write_file, file_name_mp3, result_bytes)
932
-
933
- upload_result = False
934
- for up_att in range(3):
935
- res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", f"🎙️ صدای خروجی با مدل {model_name} آماده است!")
936
- if res is True:
937
- upload_result = True
938
- break
939
- await asyncio.sleep(4)
940
-
941
- if upload_result is True:
942
- if not creds.get("is_premium"):
943
- user_credits_db[str_chat_id]["voice_conv"] -= 1
944
- save_db(user_credits_db)
945
- else:
946
- await send_with_keyboard(client, chat_id, "❌ فایل پردازش شد اما امکان ارسال در روبیکا فراهم نشد.", True)
947
-
948
- if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
949
-
950
- # ==============================================================================
951
- # 🟢 پارت 13: پردازش هوش مصنوعی متنی و تصویری جیمینای و هاگینگ‌فیس
952
- # ==============================================================================
953
- # ==================================================================
954
- # سایر توابع پردازشی
955
- # ==================================================================
956
- async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
957
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
958
- creds = get_user_credits(str_chat_id)
959
- if creds["chat"] <= 0:
960
- return await send_with_keyboard(client, chat_id, "❌ اعتبار پیام‌های چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
961
-
962
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
963
-
964
- proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
965
- history = user_states[chat_id].get("history",[])
966
- new_parts =[]
967
-
968
- is_image = True
969
- has_non_image_file = False
970
-
971
- if prompt: new_parts.append({"text": prompt})
972
- elif file_bytes: new_parts.append({"text": "لطفاً این فایل را به دقت بررسی کن."})
973
-
974
- if file_bytes and file_name:
975
- base64_data = base64.b64encode(file_bytes).decode('utf-8')
976
- mime_type, _ = mimetypes.guess_type(file_name)
977
- if not mime_type:
978
- if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg"
979
- elif file_name.endswith('.png'): mime_type = "image/png"
980
- elif file_name.endswith('.pdf'): mime_type = "application/pdf"
981
- elif file_name.endswith('.mp4'): mime_type = "video/mp4"
982
- elif file_name.endswith('.mp3'): mime_type = "audio/mp3"
983
- elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg"
984
- elif file_name.endswith('.wav'): mime_type = "audio/wav"
985
- else: mime_type = "image/jpeg"
986
-
987
- is_image = mime_type.startswith('image/')
988
- if not is_image:
989
- has_non_image_file = True
990
-
991
- new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
992
-
993
- if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
994
- else: history.append({"role": "user", "parts": new_parts})
995
-
996
- if len(history) > 40:
997
- history = history[-40:]
998
- if history[0]["role"] == "model": history = history[1:]
999
-
1000
- final_answer = None
1001
- for attempt in range(3):
1002
- keys_to_try = get_next_gemini_keys(100)
1003
- async with aiohttp.ClientSession() as session:
1004
- for key in keys_to_try:
1005
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1006
- payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
1007
- try:
1008
- async with session.post(url, json=payload, timeout=60) as response:
1009
- if response.status == 200:
1010
- data = await response.json()
1011
- try:
1012
- final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
1013
- break
1014
- except (KeyError, IndexError): continue
1015
- except Exception: continue
1016
- if final_answer: break
1017
- await asyncio.sleep(2)
1018
-
1019
- if not final_answer:
1020
- if has_non_image_file:
1021
- if history and history[-1]["role"] == "user": history.pop()
1022
- try:
1023
- if proc_msg:
1024
- msg_id = getattr(proc_msg, 'message_id', None)
1025
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1026
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1027
- except Exception: pass
1028
- await send_with_keyboard(client, chat_id, "❌ متأسفانه سرور اصلی در حال حاضر شلوغ است و در این شرایط **فعلاً تنها امکان تحلیل تصاویر** توسط سرور جایگزین در دسترس است.", False)
1029
- return
1030
-
1031
- if HF_TOKENS:
1032
- hf_messages =[]
1033
- for msg in history:
1034
- role = "assistant" if msg["role"] == "model" else "user"
1035
- content_parts =[]
1036
- for part in msg["parts"]:
1037
- if "text" in part:
1038
- content_parts.append({"type": "text", "text": part["text"]})
1039
- elif "inlineData" in part:
1040
- mime_t = part["inlineData"]["mimeType"]
1041
- b64_d = part["inlineData"]["data"]
1042
- if mime_t.startswith('image/'):
1043
- content_parts.append({
1044
- "type": "image_url",
1045
- "image_url": {"url": f"data:{mime_t};base64,{b64_d}"}
1046
- })
1047
- if content_parts:
1048
- hf_messages.append({"role": role, "content": content_parts})
1049
-
1050
- for attempt in range(3):
1051
- keys_to_try_hf = HF_TOKENS.copy()
1052
- random.shuffle(keys_to_try_hf)
1053
- async with aiohttp.ClientSession() as session:
1054
- for hf_key in keys_to_try_hf:
1055
- url = "https://router.huggingface.co/v1/chat/completions"
1056
- headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1057
- payload = {
1058
- "model": "google/gemma-4-31B-it:novita",
1059
- "messages": hf_messages,
1060
- "max_tokens": 4096
1061
- }
1062
- try:
1063
- async with session.post(url, headers=headers, json=payload, timeout=60) as response:
1064
- if response.status == 200:
1065
- data = await response.json()
1066
- final_answer = data["choices"][0]["message"]["content"]
1067
- break
1068
- except Exception:
1069
- continue
1070
- if final_answer: break
1071
- await asyncio.sleep(2)
1072
-
1073
- try:
1074
- if proc_msg:
1075
- msg_id = getattr(proc_msg, 'message_id', None)
1076
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1077
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1078
- except Exception: pass
1079
-
1080
- if not final_answer:
1081
- if history and history[-1]["role"] == "user": history.pop()
1082
- await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", False)
1083
- return
1084
-
1085
- history.append({"role": "model", "parts":[{"text": final_answer}]})
1086
- user_states[chat_id]["history"] = history
1087
-
1088
- try:
1089
- max_len = 1000
1090
- chunks =[]
1091
- temp_text = final_answer
1092
- while len(temp_text) > max_len:
1093
- split_idx = temp_text.rfind('\n', 0, max_len)
1094
- if split_idx == -1: split_idx = temp_text.rfind(' ', 0, max_len)
1095
- if split_idx == -1: split_idx = max_len
1096
- chunks.append(temp_text[:split_idx])
1097
- temp_text = temp_text[split_idx:].strip()
1098
- if temp_text: chunks.append(temp_text)
1099
-
1100
- success_sent = False
1101
- for idx, chunk in enumerate(chunks):
1102
- if idx != len(chunks) - 1: chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇"
1103
- try:
1104
- res = await send_with_keyboard(client, chat_id, chunk, False)
1105
- if res: success_sent = True
1106
- await asyncio.sleep(2.5)
1107
- except Exception: await asyncio.sleep(2.5)
1108
-
1109
- if success_sent and not creds.get("is_premium"):
1110
- user_credits_db[str_chat_id]["chat"] -= 1
1111
- save_db(user_credits_db)
1112
-
1113
- except Exception:
1114
- await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
1115
-
1116
- # ==============================================================================
1117
- # 🟢 پارت 14: ساخت عکس با هوش مصنوعی
1118
- # ==============================================================================
1119
- async def process_image(client, chat_id, prompt, size_choice="1"):
1120
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1121
- creds = get_user_credits(str_chat_id)
1122
- if creds["image"] <= 0:
1123
- return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت عکس شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1124
-
1125
- if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
1126
-
1127
- proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما...\n(تبدیل به پرامپت حرفه‌ای)", False)
1128
- enhanced_prompt = prompt
1129
- gemini_sys_prompt = f"You are an expert AI image generation prompt engineer. Translate the following user input to English, and enhance it with high-quality, highly detailed, 4k resolution, cinematic lighting, and visually striking descriptive keywords. Return ONLY the final English prompt string.\nUser input: {prompt}"
1130
-
1131
- if GEMINI_KEYS:
1132
- keys_to_try_gemini = get_next_gemini_keys(100)
1133
- async with aiohttp.ClientSession() as session:
1134
- for key in keys_to_try_gemini:
1135
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1136
- payload = {"contents": [{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
1137
- try:
1138
- async with session.post(url, json=payload, timeout=20) as response:
1139
- if response.status == 200:
1140
- data = await response.json()
1141
- enhanced_prompt = data["candidates"][0]["content"]["parts"][0]["text"].strip()
1142
- break
1143
- except Exception: continue
1144
-
1145
- if enhanced_prompt == prompt and HF_TOKENS:
1146
- keys_to_try_hf = HF_TOKENS.copy()
1147
- random.shuffle(keys_to_try_hf)
1148
- async with aiohttp.ClientSession() as session:
1149
- for hf_key in keys_to_try_hf:
1150
- url = "https://router.huggingface.co/v1/chat/completions"
1151
- headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1152
- payload = {
1153
- "model": "google/gemma-4-31B-it:novita",
1154
- "messages":[{"role": "user", "content":[{"type": "text", "text": gemini_sys_prompt}]}],
1155
- "max_tokens": 1024
1156
- }
1157
- try:
1158
- async with session.post(url, headers=headers, json=payload, timeout=20) as response:
1159
- if response.status == 200:
1160
- data = await response.json()
1161
- enhanced_prompt = data["choices"][0]["message"]["content"].strip()
1162
- break
1163
- except Exception:
1164
- continue
1165
-
1166
- try:
1167
- if proc_msg:
1168
- msg_id = getattr(proc_msg, 'message_id', None)
1169
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1170
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1171
- except Exception: pass
1172
-
1173
- w, h = 1024, 1024
1174
- size_name = "مربع (1:1) ⬛"
1175
- if size_choice == "2":
1176
- w, h = 768, 1344
1177
- size_name = "عمودی (9:16) 📱"
1178
- elif size_choice == "3":
1179
- w, h = 1344, 768
1180
- size_name = "افقی (16:9) 🖥️"
1181
- elif size_choice == "4":
1182
- w, h = 1024, 768
1183
- size_name = "استاندارد (4:3) 📸"
1184
-
1185
- short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
1186
- proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📏 **ابعاد:** {size_name}\n📝 **پرامپت ساخته شده:**\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
1187
-
1188
- generated_image = None
1189
- last_error_log = "هیچ اتصالی برقرار نشد."
1190
-
1191
- for attempt in range(5):
1192
- keys_to_try = HF_TOKENS.copy()
1193
- random.shuffle(keys_to_try)
1194
- for token in keys_to_try:
1195
- try:
1196
- hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
1197
- generated_image = await hf_client.text_to_image(
1198
- enhanced_prompt,
1199
- model="Tongyi-MAI/Z-Image-Turbo",
1200
- width=w,
1201
- height=h
1202
- )
1203
- break
1204
- except Exception as e:
1205
- last_error_log = str(e)
1206
- continue
1207
- if generated_image: break
1208
- await asyncio.sleep(2)
1209
-
1210
- try:
1211
- if proc_msg:
1212
- msg_id = getattr(proc_msg, 'message_id', None)
1213
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1214
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1215
- except Exception: pass
1216
-
1217
- if not generated_image:
1218
- return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
1219
-
1220
- try:
1221
- file_name = f"image_{uuid.uuid4().hex}.jpg"
1222
- await asyncio.to_thread(sync_save_image, generated_image, file_name)
1223
- await asyncio.sleep(1)
1224
- caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n📏 ابعاد تصویر: {size_name}\n✨ ایده اولیه: {prompt}"
1225
-
1226
- upload_result = False
1227
- error_log_img = ""
1228
- for up_att in range(3):
1229
- res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
1230
- if res is True:
1231
- upload_result = True
1232
- break
1233
- else:
1234
- error_log_img = res
1235
- await asyncio.sleep(4)
1236
-
1237
- if upload_result is True:
1238
- if not creds.get("is_premium"):
1239
- user_credits_db[str_chat_id]["image"] -= 1
1240
- save_db(user_credits_db)
1241
- else:
1242
- await send_with_keyboard(client, chat_id, f"❌ عکس ساخته شد اما آپلود در روبیکا با خطا مواجه شد:\n`{str(error_log_img)[:800]}`", True)
1243
-
1244
- if os.path.exists(file_name): os.remove(file_name)
1245
- except Exception as e:
1246
- await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره و ارسال عکس:\n{str(e)[:150]}", True)
1247
-
1248
- # ==============================================================================
1249
- # 🟢 پارت 15: توابع ترجمه و ویرایش عکس با هوش مصنوعی (Flux.2)
1250
- # ==============================================================================
1251
- async def translate_text_aloha(prompt_text):
1252
- session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
1253
- join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join"
1254
- payload = {
1255
- "data":[prompt_text, "انگلیسی (آمریکا) - جنی (زن)", 0, 0, 0],
1256
- "fn_index": 1,
1257
- "session_hash": session_hash
1258
- }
1259
-
1260
- try:
1261
- async with aiohttp.ClientSession() as session:
1262
- async with session.post(join_url, json=payload, timeout=20) as resp:
1263
- if resp.status != 200:
1264
- return prompt_text
1265
-
1266
- data_url = f"https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/data?session_hash={session_hash}"
1267
- async with session.get(data_url, timeout=60) as resp:
1268
- async for line_bytes in resp.content:
1269
- line = line_bytes.decode('utf-8').strip()
1270
- if line.startswith("data: "):
1271
- try:
1272
- json_data = json.loads(line[6:])
1273
- if json_data.get("msg") == "process_completed":
1274
- if json_data.get("success"):
1275
- return json_data["output"]["data"][0]
1276
- break
1277
- except Exception:
1278
- pass
1279
- except Exception:
1280
- pass
1281
-
1282
- return prompt_text
1283
-
1284
- async def process_image_edit(client, chat_id, image_bytes, prompt):
1285
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1286
- creds = get_user_credits(str_chat_id)
1287
- if creds["edit_image"] <= 0:
1288
- return await send_with_keyboard(client, chat_id, "❌ اعتبار ویرایش عکس شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1289
-
1290
- if not HF_TOKENS:
1291
- return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
1292
-
1293
- proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال ترجمه دستور شما توسط اسپیس و اعمال جادوی FLUX.2...\n(این فرآیند ممکن است کمی طول بکشد)", False)
1294
-
1295
- translated_prompt = await translate_text_aloha(prompt)
1296
- if not translated_prompt or translated_prompt.strip() == "":
1297
- translated_prompt = prompt
1298
-
1299
- generated_image = None
1300
- last_error_log = "سرور پاسخ نداد."
1301
-
1302
- for attempt in range(5):
1303
- keys_to_try = HF_TOKENS.copy()
1304
- random.shuffle(keys_to_try)
1305
- for token in keys_to_try:
1306
- try:
1307
- hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
1308
- generated_image = await hf_client.image_to_image(
1309
- image_bytes,
1310
- prompt=translated_prompt,
1311
- model="black-forest-labs/FLUX.2-dev"
1312
- )
1313
- break
1314
- except Exception as e:
1315
- last_error_log = str(e)
1316
- continue
1317
- if generated_image: break
1318
- await asyncio.sleep(2)
1319
-
1320
- try:
1321
- if proc_msg:
1322
- msg_id = getattr(proc_msg, 'message_id', None)
1323
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1324
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1325
- except Exception: pass
1326
-
1327
- if not generated_image:
1328
- return await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
1329
-
1330
- try:
1331
- file_name = f"edited_flux_{uuid.uuid4().hex}.jpg"
1332
- await asyncio.to_thread(sync_save_image, generated_image, file_name)
1333
- await asyncio.sleep(1)
1334
- caption_text = f"🪄 ویرایش عکس با هوش مصنوعی Flux.2 انجام شد!\n\n✨ تغییرات خواسته شده: {prompt}\n🔤 متن ارسال شده به هوش: {translated_prompt}"
1335
-
1336
- upload_result = False
1337
- error_log_edit = ""
1338
- for up_att in range(3):
1339
- res = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
1340
- if res is True:
1341
- upload_result = True
1342
- break
1343
- else:
1344
- error_log_edit = res
1345
- await asyncio.sleep(4)
1346
-
1347
- if upload_result is True:
1348
- if not creds.get("is_premium"):
1349
- user_credits_db[str_chat_id]["edit_image"] -= 1
1350
- save_db(user_credits_db)
1351
- else:
1352
- await send_with_keyboard(client, chat_id, f"❌ عکس ساخته شد اما خطا در ارسال به روبیکا رخ داد:\n`{str(error_log_edit)[:800]}`", True)
1353
-
1354
- if os.path.exists(file_name): os.remove(file_name)
1355
- except Exception as e:
1356
- await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
1357
-
1358
- # ==============================================================================
1359
- # 🟢 پارت 16: ساخت صدا از روی متن (تبدیل متن به صدا - TTS)
1360
- # ==============================================================================
1361
- async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
1362
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1363
- creds = get_user_credits(str_chat_id)
1364
- if creds["tts"] <= 0:
1365
- return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل متن به صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1366
-
1367
- try:
1368
- proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
1369
- payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
1370
- headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
1371
-
1372
- audio_bytes = None
1373
- last_error = "پاسخی دریافت نشد"
1374
-
1375
- for attempt in range(10):
1376
- workers = WORKER_URLS.copy()
1377
- random.shuffle(workers)
1378
- async with aiohttp.ClientSession(headers=headers, timeout=aiohttp.ClientTimeout(total=600)) as session:
1379
- for worker_url in workers[:3]:
1380
- try:
1381
- async with session.post(worker_url, json=payload) as response:
1382
- if response.status == 200:
1383
- content_type = response.headers.get('Content-Type', '')
1384
- if 'audio' in content_type or response.content_length > 1000:
1385
- audio_bytes = await response.read()
1386
- break
1387
- else: last_error = "فایل نامعتبر"
1388
- else: last_error = f"ارور ({response.status})"
1389
- except Exception as e:
1390
- last_error = f"خطا: {str(e)}"
1391
- continue
1392
- if audio_bytes: break
1393
- await asyncio.sleep(2)
1394
-
1395
- try:
1396
- if proc_msg:
1397
- msg_id = getattr(proc_msg, 'message_id', None)
1398
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1399
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1400
- except Exception: pass
1401
-
1402
- if audio_bytes:
1403
- file_name_mp3 = f"audio_{uuid.uuid4().hex}.mp3"
1404
- await asyncio.to_thread(sync_write_file, file_name_mp3, audio_bytes)
1405
- await asyncio.sleep(1)
1406
-
1407
- upload_result_file = False
1408
- error_log_tts = ""
1409
- for up_att in range(3):
1410
- res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
1411
- if res is True:
1412
- upload_result_file = True
1413
- break
1414
- else:
1415
- error_log_tts = res
1416
- await asyncio.sleep(4)
1417
-
1418
- if upload_result_file is True:
1419
- if not creds.get("is_premium"):
1420
- user_credits_db[str_chat_id]["tts"] -= 1
1421
- save_db(user_credits_db)
1422
- else:
1423
- await send_with_keyboard(client, chat_id, f"❌ فایل صدا ساخته شد اما سرور روبیکا اجازه آپلود نداد:\n`{str(error_log_tts)[:800]}`", True)
1424
-
1425
- if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1426
- else:
1427
- await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
1428
- except Exception: traceback.print_exc()
1429
-
1430
- # ==============================================================================
1431
- # 🟢 پارت 17: سیستم ساخت پادکست
1432
- # ==============================================================================
1433
- async def process_podcast(client, chat_id, prompt):
1434
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1435
- creds = get_user_credits(str_chat_id)
1436
- if creds["podcast"] <= 0:
1437
- return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت پادکست شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1438
-
1439
- proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست توسط هوش مصنوعی...\n(لطفاً صبور باشید)", False)
1440
- available_speakers =[]
1441
- for num_key, (spk_name, spk_id) in SPEAKERS.items():
1442
- gender = "male" if "مرد" in spk_name else "female"
1443
- available_speakers.append({"id": spk_id, "name": spk_name.split(' (')[0], "gender": gender})
1444
-
1445
- url_create = "https://opera8-podgen.hf.space/api/create-full-podcast"
1446
- payload_create = {"prompt": prompt, "available_speakers": available_speakers}
1447
-
1448
- async with aiohttp.ClientSession() as session:
1449
- try:
1450
- async with session.post(url_create, json=payload_create, timeout=60) as resp:
1451
- if resp.status != 202: return await send_with_keyboard(client, chat_id, f"❌ خطا در سرور پادکست: وضعیت {resp.status}", True)
1452
- task_id = (await resp.json()).get("task_id")
1453
- except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور پادکست:\n{str(e)}", True)
1454
-
1455
- url_status = f"https://opera8-podgen.hf.space/api/podcast-status/{task_id}"
1456
- script_data = None
1457
- for _ in range(500):
1458
- await asyncio.sleep(3)
1459
- try:
1460
- async with session.get(url_status) as resp:
1461
- if resp.status == 200:
1462
- status_data = await resp.json()
1463
- if status_data.get("status") == "completed":
1464
- script_data = status_data.get("data", {}).get("script",[])
1465
- break
1466
- elif status_data.get("status") == "failed":
1467
- return await send_with_keyboard(client, chat_id, "❌ متأسفانه هوش مصنوعی نتوانست برای این موضوع سناریو بنویسد.", True)
1468
- except Exception: pass
1469
-
1470
- if not script_data: return await send_with_keyboard(client, chat_id, "❌ زمان انتظار برای نوشتن سناریو به پایان رسید.", True)
1471
-
1472
- try:
1473
- if proc_msg:
1474
- msg_id = getattr(proc_msg, 'message_id', None)
1475
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1476
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1477
- except: pass
1478
-
1479
- proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال ریکورد و م��کس دیالوگ‌های گویندگان (شامل {len(script_data)} نوبت صحبت)...\nاین مرحله زمان‌بر است...", False)
1480
-
1481
- combined_audio = AudioSegment.empty()
1482
- url_generate = "https://opera8-podgen.hf.space/api/generate"
1483
-
1484
- for index, turn in enumerate(script_data):
1485
- payload_gen = {"text": turn["dialogue"], "speaker": turn["speaker_id"], "temperature": 0.9}
1486
- chunk_audio_bytes = None
1487
-
1488
- for attempt in range(10):
1489
- try:
1490
- async with session.post(url_generate, json=payload_gen, timeout=120) as resp:
1491
- if resp.status == 200:
1492
- chunk_audio_bytes = await resp.read()
1493
- break
1494
- except Exception: await asyncio.sleep(2)
1495
-
1496
- if not chunk_audio_bytes:
1497
- return await send_with_keyboard(client, chat_id, f"❌ خطا در تولید صدای بخش {index+1} از سرور. عملیات متوقف شد.", True)
1498
-
1499
- try:
1500
- combined_audio = await asyncio.to_thread(sync_combine_audio, combined_audio, chunk_audio_bytes)
1501
- except Exception as e:
1502
- return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا:\n{str(e)}", True)
1503
-
1504
- file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
1505
- await asyncio.to_thread(sync_export_audio, combined_audio, file_name_mp3)
1506
-
1507
- try:
1508
- if proc_msg:
1509
- msg_id = getattr(proc_msg, 'message_id', None)
1510
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1511
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1512
- except: pass
1513
-
1514
- caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
1515
-
1516
- upload_result_file = False
1517
- error_log_pod = ""
1518
- for up_att in range(3):
1519
- res = await helper_upload_file(client, chat_id, file_name_mp3, "Music", caption_file)
1520
- if res is True:
1521
- upload_result_file = True
1522
- break
1523
- else:
1524
- error_log_pod = res
1525
- await asyncio.sleep(5)
1526
-
1527
- if upload_result_file is True:
1528
- if not creds.get("is_premium"):
1529
- user_credits_db[str_chat_id]["podcast"] -= 1
1530
- save_db(user_credits_db)
1531
- else:
1532
- await send_with_keyboard(client, chat_id, f"❌ پادکست ساخته شد اما روبیکا پس از ده‌ها تلاش خطای آپلود داد.\n\n`{str(error_log_pod)[:800]}`", True)
1533
-
1534
- if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
1535
-
1536
- # ==============================================================================
1537
- # 🟢 پارت 18: استخراج متن از صدا (STT) و تحلیل انواع فایل با هوش مصنوعی
1538
- # ==============================================================================
1539
- async def process_stt(client, chat_id, audio_bytes, file_name):
1540
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1541
- creds = get_user_credits(str_chat_id)
1542
- if creds["stt"] <= 0:
1543
- return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل صدا به متن شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1544
-
1545
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
1546
-
1547
- proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن...", False)
1548
- base64_data = base64.b64encode(audio_bytes).decode('utf-8')
1549
- mime_type, _ = mimetypes.guess_type(file_name)
1550
- if not mime_type: mime_type = "audio/ogg"
1551
-
1552
- prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
1553
-
1554
- transcribed_text = None
1555
- for attempt in range(5):
1556
- keys_to_try = get_next_gemini_keys(100)
1557
- async with aiohttp.ClientSession() as session:
1558
- for key in keys_to_try:
1559
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1560
- payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.2}}
1561
- try:
1562
- async with session.post(url, json=payload, timeout=60) as response:
1563
- if response.status == 200:
1564
- data = await response.json()
1565
- transcribed_text = data["candidates"][0]["content"]["parts"][0]["text"]
1566
- break
1567
- except Exception: continue
1568
- if transcribed_text: break
1569
- await asyncio.sleep(2)
1570
-
1571
- try:
1572
- if proc_msg:
1573
- msg_id = getattr(proc_msg, 'message_id', None)
1574
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1575
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1576
- except Exception: pass
1577
-
1578
- if transcribed_text:
1579
- sent = await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
1580
- if sent and not creds.get("is_premium"):
1581
- user_credits_db[str_chat_id]["stt"] -= 1
1582
- save_db(user_credits_db)
1583
- else:
1584
- await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
1585
-
1586
- async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
1587
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1588
- creds = get_user_credits(str_chat_id)
1589
- if creds["file"] <= 0:
1590
- return await send_with_keyboard(client, chat_id, "❌ اعتبار تحلیل فایل شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1591
-
1592
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False)
1593
-
1594
- proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
1595
- base64_data = base64.b64encode(file_bytes).decode('utf-8')
1596
- mime_type, _ = mimetypes.guess_type(file_name)
1597
- if not mime_type:
1598
- if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg"
1599
- elif file_name.endswith('.png'): mime_type = "image/png"
1600
- elif file_name.endswith('.pdf'): mime_type = "application/pdf"
1601
- elif file_name.endswith('.mp4'): mime_type = "video/mp4"
1602
- elif file_name.endswith('.mp3'): mime_type = "audio/mp3"
1603
- elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg"
1604
- elif file_name.endswith('.wav'): mime_type = "audio/wav"
1605
- else: mime_type = "image/jpeg"
1606
-
1607
- is_image = mime_type.startswith('image/')
1608
-
1609
- final_answer = None
1610
- for attempt in range(5):
1611
- keys_to_try = get_next_gemini_keys(100)
1612
- async with aiohttp.ClientSession() as session:
1613
- for key in keys_to_try:
1614
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1615
- payload = {"contents": [{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.6}}
1616
- try:
1617
- async with session.post(url, json=payload, timeout=45) as response:
1618
- if response.status == 200:
1619
- data = await response.json()
1620
- final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
1621
- break
1622
- except Exception: continue
1623
- if final_answer: break
1624
- await asyncio.sleep(2)
1625
-
1626
- if not final_answer:
1627
- if is_image and HF_TOKENS:
1628
- for attempt in range(5):
1629
- keys_to_try_hf = HF_TOKENS.copy()
1630
- random.shuffle(keys_to_try_hf)
1631
-
1632
- hf_messages =[
1633
- {
1634
- "role": "user",
1635
- "content":[
1636
- {"type": "text", "text": prompt},
1637
- {
1638
- "type": "image_url",
1639
- "image_url": {"url": f"data:{mime_type};base64,{base64_data}"}
1640
- }
1641
- ]
1642
- }
1643
- ]
1644
-
1645
- async with aiohttp.ClientSession() as session:
1646
- for hf_key in keys_to_try_hf:
1647
- url = "https://router.huggingface.co/v1/chat/completions"
1648
- headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1649
- payload = {
1650
- "model": "google/gemma-4-31B-it:novita",
1651
- "messages": hf_messages,
1652
- "max_tokens": 4096
1653
- }
1654
- try:
1655
- async with session.post(url, headers=headers, json=payload, timeout=60) as response:
1656
- if response.status == 200:
1657
- data = await response.json()
1658
- final_answer = data["choices"][0]["message"]["content"]
1659
- break
1660
- except Exception:
1661
- continue
1662
- if final_answer: break
1663
- await asyncio.sleep(2)
1664
-
1665
- try:
1666
- if proc_msg:
1667
- msg_id = getattr(proc_msg, 'message_id', None)
1668
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1669
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1670
- except Exception: pass
1671
-
1672
- if final_answer:
1673
- sent = await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
1674
- if sent and not creds.get("is_premium"):
1675
- user_credits_db[str_chat_id]["file"] -= 1
1676
- save_db(user_credits_db)
1677
- else:
1678
- if not is_image:
1679
- await send_with_keyboard(client, chat_id, "❌ متأسفانه سرور اصلی در حال حاضر شلوغ است و در این شرایط **فعلاً تنها امکان تحلیل تصاویر** توسط سرور جایگزین در دسترس است.", True)
1680
- else:
1681
- await send_with_keyboard(client, chat_id, "❌ تمامی سرورها شلوغ هستند. لطفاً بعداً امتحان کنید.", True)
1682
-
1683
- # ==============================================================================
1684
- # 🟢 پارت 19: ساخت مقاله و خروجی فایل متنی (Word/PDF)
1685
- # ==============================================================================
1686
- async def process_create_file(client, chat_id, topic):
1687
- str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1688
- creds = get_user_credits(str_chat_id)
1689
-
1690
- if creds["chat"] <= 0:
1691
- return await send_with_keyboard(client, chat_id, "❌ اعتبار چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
1692
-
1693
- if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
1694
-
1695
- proc_msg = await send_with_keyboard(client, chat_id, "✍️ در حال تحقیق و نگارش مقاله جامع و حرفه‌ای...\n(این عملیات با توجه به طولانی بودن متن ممکن است کمی طول بکشد)", False)
1696
-
1697
- ai_prompt = f"یک مقاله بسیار جامع، کاملا حرفه‌ای، بسیار طولانی و با جزئیات کامل درباره موضوع زیر به زبان فارسی بنویس. فقط متن مقاله را بده و هیچ توضیح اضافه‌ای نده:\n\nموضوع: {topic}"
1698
-
1699
- article_text = None
1700
- for attempt in range(5):
1701
- keys_to_try = get_next_gemini_keys(100)
1702
- async with aiohttp.ClientSession() as session:
1703
- for key in keys_to_try:
1704
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
1705
- payload = {"contents":[{"parts":[{"text": ai_prompt}]}], "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
1706
- try:
1707
- async with session.post(url, json=payload, timeout=60) as response:
1708
- if response.status == 200:
1709
- data = await response.json()
1710
- article_text = data["candidates"][0]["content"]["parts"][0]["text"]
1711
- break
1712
- except Exception: continue
1713
- if article_text: break
1714
- await asyncio.sleep(2)
1715
-
1716
- if not article_text and HF_TOKENS:
1717
- for attempt in range(5):
1718
- keys_to_try_hf = HF_TOKENS.copy()
1719
- random.shuffle(keys_to_try_hf)
1720
- async with aiohttp.ClientSession() as session:
1721
- for hf_key in keys_to_try_hf:
1722
- url = "https://router.huggingface.co/v1/chat/completions"
1723
- headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
1724
- payload = {
1725
- "model": "google/gemma-4-31B-it:novita",
1726
- "messages":[{"role": "user", "content":[{"type": "text", "text": ai_prompt}]}],
1727
- "max_tokens": 4096
1728
- }
1729
- try:
1730
- async with session.post(url, headers=headers, json=payload, timeout=60) as response:
1731
- if response.status == 200:
1732
- data = await response.json()
1733
- article_text = data["choices"][0]["message"]["content"]
1734
- break
1735
- except Exception: continue
1736
- if article_text: break
1737
- await asyncio.sleep(2)
1738
-
1739
- if not article_text:
1740
- return await send_with_keyboard(client, chat_id, "❌ سرور تولید متن شلوغ است، لطفاً بعداً تلاش کنید.", True)
1741
-
1742
- try:
1743
- if proc_msg:
1744
- msg_id = getattr(proc_msg, 'message_id', None)
1745
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1746
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1747
- except Exception: pass
1748
-
1749
- proc_msg = await send_with_keyboard(client, chat_id, "📄 مقاله با موفقیت نوشته شد! در حال ارتباط با سرور و تبدیل به فایل‌های PDF و Word...\n(لطفا صبور باشید)", False)
1750
-
1751
- converter_url = "https://opera8-texttopdf.hf.space/"
1752
- uid = uuid.uuid4().hex
1753
-
1754
- pdf_success = False
1755
- for attempt in range(30):
1756
- try:
1757
- pdf_bytes = None
1758
- async with aiohttp.ClientSession() as session:
1759
- form_data = aiohttp.FormData()
1760
- form_data.add_field('content', article_text)
1761
- form_data.add_field('format', 'pdf')
1762
- async with session.post(converter_url, data=form_data, timeout=90) as resp:
1763
- if resp.status == 200:
1764
- data_bytes = await resp.read()
1765
- if data_bytes and len(data_bytes) > 100:
1766
- pdf_bytes = data_bytes
1767
-
1768
- if pdf_bytes:
1769
- filename = f"Article_{uid}.pdf"
1770
- await asyncio.to_thread(sync_write_file, filename, pdf_bytes)
1771
-
1772
- res_upload = False
1773
- for _ in range(3):
1774
- r = await helper_upload_file(client, chat_id, filename, "File", f"📄 فایل PDF مقاله شما:\n\n💡 موضوع: {topic}")
1775
- if r is True:
1776
- res_upload = True
1777
- break
1778
- await asyncio.sleep(4)
1779
-
1780
- if os.path.exists(filename):
1781
- os.remove(filename)
1782
-
1783
- if res_upload is True:
1784
- pdf_success = True
1785
- break
1786
- except Exception as e:
1787
- print(f"PDF error (attempt {attempt+1}):", e)
1788
-
1789
- await asyncio.sleep(4)
1790
-
1791
- await asyncio.sleep(3.5)
1792
-
1793
- docx_success = False
1794
- for attempt in range(30):
1795
- try:
1796
- docx_bytes = None
1797
- async with aiohttp.ClientSession() as session:
1798
- form_data = aiohttp.FormData()
1799
- form_data.add_field('content', article_text)
1800
- form_data.add_field('format', 'docx')
1801
- async with session.post(converter_url, data=form_data, timeout=90) as resp:
1802
- if resp.status == 200:
1803
- data_bytes = await resp.read()
1804
- if data_bytes and len(data_bytes) > 100:
1805
- docx_bytes = data_bytes
1806
-
1807
- if docx_bytes:
1808
- filename = f"Article_{uid}.docx"
1809
- await asyncio.to_thread(sync_write_file, filename, docx_bytes)
1810
-
1811
- res_upload = False
1812
- for _ in range(3):
1813
- r = await helper_upload_file(client, chat_id, filename, "File", f"📝 فایل Word (DOCX) مقاله شما:\n\n💡 موضوع: {topic}")
1814
- if r is True:
1815
- res_upload = True
1816
- break
1817
- await asyncio.sleep(4)
1818
-
1819
- if os.path.exists(filename):
1820
- os.remove(filename)
1821
-
1822
- if res_upload is True:
1823
- docx_success = True
1824
- break
1825
- except Exception as e:
1826
- print(f"DOCX error (attempt {attempt+1}):", e)
1827
-
1828
- await asyncio.sleep(4)
1829
-
1830
- try:
1831
- if proc_msg:
1832
- msg_id = getattr(proc_msg, 'message_id', None)
1833
- if isinstance(proc_msg, dict): msg_id = proc_msg.get('message_update', {}).get('message_id') or proc_msg.get('message_id')
1834
- if msg_id: await client.delete_messages(chat_id,[msg_id])
1835
- except Exception: pass
1836
-
1837
- if pdf_success and docx_success:
1838
- if not creds.get("is_premium"):
1839
- user_credits_db[str_chat_id]["chat"] -= 1
1840
- save_db(user_credits_db)
1841
- await send_with_keyboard(client, chat_id, "✅ مقاله شما با موفقیت به صورت هر دو فایل (PDF و Word) تحویل داده شد!", True)
1842
- elif pdf_success or docx_success:
1843
- if not creds.get("is_premium"):
1844
- user_credits_db[str_chat_id]["chat"] -= 1
1845
- save_db(user_credits_db)
1846
- await send_with_keyboard(client, chat_id, "⚠️ یکی از فایل‌ها با موفقیت ارسال شد اما دیگری پس از تلاش‌های مکرر سرور با خطا مواجه شد.", True)
1847
- else:
1848
- await send_with_keyboard(client, chat_id, "❌ متأسفانه پس از تلاش‌های مکرر، سرور قادر به ساخت و ارسال هیچ‌یک از فایل‌ها نبود و اعتباری از شما کسر نشد.", True)
1849
-
1850
- # ==============================================================================
1851
- # 🔴 پا��ت 20: نسخه پاکسازی اضطراری (مخصوص تخلیه صف در دیتابیس جدید v3)
1852
- # ==============================================================================
1853
-
1854
- if not bot_token:
1855
- print("خطا: توکن وارد نشده!")
1856
- else:
1857
- bot = BotClient(bot_token)
1858
-
1859
- @bot.on_update(filters.private)
1860
- async def main_handler(client, update):
1861
- try:
1862
- # فقط استخراج آیدی پیام
1863
- msg_obj = getattr(update, "message", None) or getattr(update, "new_message", None)
1864
- msg_id = getattr(update, "message_id", None)
1865
- if not msg_id and msg_obj:
1866
- msg_id = msg_obj.get("message_id") if isinstance(msg_obj, dict) else getattr(msg_obj, "message_id", None)
1867
-
1868
- if not msg_id: return
1869
- str_msg_id = str(msg_id).strip()
1870
-
1871
- # ثبت در دیتابیس v3 بدون فرستادن هیچ پاسخی
1872
- if not is_message_processed(str_msg_id):
1873
- mark_message_processed(str_msg_id)
1874
- print(f"🗑️ [V3-CLEARING] پیام {str_msg_id} ثبت شد.")
1875
-
1876
- except Exception:
1877
- pass
1878
-
1879
- if __name__ == "__main__":
1880
- threading.Thread(target=run_flask, daemon=True).start()
1881
- if bot_token:
1882
- print("⚠️ وضعیت: در حال تخلیه صف پیام‌ها در دیتابیس v3... لطفاً تا توقف لاگ‌ها صبر کنید.")
1883
- bot.run()