Opera8 commited on
Commit
2e7f4e0
·
verified ·
1 Parent(s): 31663ed

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +1484 -0
main.py ADDED
@@ -0,0 +1,1484 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import threading
4
+ import random
5
+ import aiohttp
6
+ import traceback
7
+ import asyncio
8
+ import base64
9
+ import mimetypes
10
+ import io
11
+ import json
12
+ import datetime
13
+ import string
14
+ import uuid
15
+ from flask import Flask
16
+
17
+ # کتابخانه‌های ربات تلگرام/بله
18
+ import telebot
19
+ from telebot.async_telebot import AsyncTeleBot
20
+ from telebot import async_apihelper
21
+ from telebot.types import ReplyKeyboardMarkup, KeyboardButton
22
+
23
+ # ایمپورت‌های هوش مصنوعی، کار با فایل صوتی و دیتابیس هاگینگ فیس
24
+ from huggingface_hub import AsyncInferenceClient, HfApi, hf_hub_download
25
+ from PIL import Image
26
+ from pydub import AudioSegment
27
+
28
+ # تنظیم آدرس API برای اتصال به سرورهای پیام‌رسان بله
29
+ async_apihelper.API_URL = "https://tapi.bale.ai/bot{0}/{1}"
30
+
31
+ # --- کد مدیریت برای ارتقای کاربران بدون نیاز به لاگین ---
32
+ ADMIN_CODE = "3011"
33
+
34
+ # متغیر سراسری برای ذخیره آیدی خود ربات (جلوگیری از جواب دادن ربات به خودش)
35
+ BOT_GUID = None
36
+
37
+ # =======================================================
38
+ # 🔥 سیستم کنترل سرعت و ضد رگبار (Burst Controller) 🔥
39
+ # =======================================================
40
+ global_burst_count = 0
41
+ global_burst_time = time.time()
42
+ burst_lock = threading.Lock()
43
+
44
+ def is_backlog_burst():
45
+ """اگر بیشتر از 5 پیام در 1 ثانیه بیاید، یعنی رگبار از سمت سرور است و رد می‌شود"""
46
+ global global_burst_count, global_burst_time
47
+ with burst_lock:
48
+ now = time.time()
49
+ if now - global_burst_time > 1.0:
50
+ global_burst_time = now
51
+ global_burst_count = 1
52
+ return False
53
+ else:
54
+ global_burst_count += 1
55
+ if global_burst_count > 5:
56
+ return True
57
+ return False
58
+
59
+ # --- سیستم دیتابیس حساب کاربری متصل به دیتاست هاگینگ فیس ---
60
+ DB_FILE = "users_db.json"
61
+ DATASET_REPO = "Opera8/Karbaran-rayegan-tedad"
62
+ HF_TOKEN_DB = os.environ.get("HF_TOKEN")
63
+ db_lock = threading.Lock()
64
+
65
+ def gregorian_to_jalali(gy, gm, gd):
66
+ g_d_m =[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
67
+ gy2 = (gy + 1) if (gm > 2) else gy
68
+ days = 355666 + (365 * gy) + ((gy2 + 3) // 4) - ((gy2 + 99) // 100) + ((gy2 + 399) // 400) + gd + g_d_m[gm - 1]
69
+ jy = -1595 + (33 * (days // 12053))
70
+ days %= 12053
71
+ jy += 4 * (days // 1461)
72
+ days %= 1461
73
+ if days > 365:
74
+ jy += (days - 1) // 365
75
+ days = (days - 1) % 365
76
+ if days < 186:
77
+ jm = 1 + (days // 31)
78
+ jd = 1 + (days % 31)
79
+ else:
80
+ jm = 7 + ((days - 186) // 30)
81
+ jd = 1 + ((days - 186) % 30)
82
+ return jy, jm, jd
83
+
84
+ def load_db():
85
+ print("در حال تلاش برای خواندن دیتابیس کاربران از دیتاست هاگینگ فیس...")
86
+ if HF_TOKEN_DB:
87
+ try:
88
+ file_path = hf_hub_download(
89
+ repo_id=DATASET_REPO,
90
+ filename=DB_FILE,
91
+ repo_type="dataset",
92
+ token=HF_TOKEN_DB
93
+ )
94
+ with open(file_path, "r", encoding="utf-8") as f:
95
+ print("✅ دیتابیس با موفقیت از دیتاست هاگینگ فیس لود شد.")
96
+ return json.load(f)
97
+ except Exception as e:
98
+ print("⚠️ فایل دیتابیس در هاگینگ فیس یافت نشد یا خطایی رخ داد (ساخت دیتابیس جدید). جزئیات:", str(e)[:100])
99
+
100
+ if os.path.exists(DB_FILE):
101
+ try:
102
+ with open(DB_FILE, "r", encoding="utf-8") as f:
103
+ return json.load(f)
104
+ except Exception:
105
+ pass
106
+ return {}
107
+
108
+ def _upload_db_background():
109
+ if HF_TOKEN_DB:
110
+ api = HfApi(token=HF_TOKEN_DB)
111
+ try:
112
+ api.upload_file(
113
+ path_or_fileobj=DB_FILE,
114
+ path_in_repo=DB_FILE,
115
+ repo_id=DATASET_REPO,
116
+ repo_type="dataset"
117
+ )
118
+ except Exception as e:
119
+ print("❌ خطا در آپلود دیتابیس به هاگینگ فیس:", str(e)[:100])
120
+
121
+ def save_db(db_data):
122
+ with db_lock:
123
+ try:
124
+ with open(DB_FILE, "w", encoding="utf-8") as f:
125
+ json.dump(db_data, f, ensure_ascii=False, indent=4)
126
+ threading.Thread(target=_upload_db_background, daemon=True).start()
127
+ except Exception as e:
128
+ print("خطا در ذخیره دیتابیس:", e)
129
+
130
+ user_credits_db = load_db()
131
+
132
+ def get_user_credits(chat_id):
133
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
134
+ today_str = datetime.date.today().isoformat()
135
+
136
+ if str_chat_id not in user_credits_db:
137
+ user_credits_db[str_chat_id] = {
138
+ "is_premium": False,
139
+ "expire_date": None,
140
+ "last_reset": "",
141
+ "chat": 10,
142
+ "image": 5,
143
+ "edit_image": 1,
144
+ "podcast": 2,
145
+ "tts": 5,
146
+ "file": 1,
147
+ "stt": 5,
148
+ "has_joined": False
149
+ }
150
+ save_db(user_credits_db)
151
+
152
+ user_data = user_credits_db[str_chat_id]
153
+ is_premium = user_data.get("is_premium", False)
154
+
155
+ if is_premium and user_data.get("expire_date"):
156
+ try:
157
+ expire_date = datetime.datetime.fromisoformat(user_data["expire_date"])
158
+ if datetime.datetime.now() > expire_date:
159
+ user_data["is_premium"] = False
160
+ user_data["expire_date"] = None
161
+ is_premium = False
162
+ except Exception:
163
+ pass
164
+
165
+ if not is_premium:
166
+ if user_data.get("last_reset") != today_str:
167
+ user_data["last_reset"] = today_str
168
+ user_data["chat"] = 10
169
+ user_data["image"] = 5
170
+ user_data["edit_image"] = 1
171
+ user_data["podcast"] = 2
172
+ user_data["tts"] = 5
173
+ user_data["file"] = 1
174
+ user_data["stt"] = 5
175
+ save_db(user_credits_db)
176
+
177
+ return user_data
178
+
179
+ def to_english_digits(text):
180
+ if not text:
181
+ return text
182
+ persian_digits = '۰۱۲۳۴۵۶۷۸۹'
183
+ arabic_digits = '٠١٢٣٤٥٦٧٨٩'
184
+ english_digits = '0123456789'
185
+ translation_table = str.maketrans(persian_digits + arabic_digits, english_digits * 2)
186
+ return str(text).translate(translation_table)
187
+
188
+ # --- تنظیمات وب سرور ---
189
+ app = Flask(__name__)
190
+
191
+ @app.route('/')
192
+ def home():
193
+ return "ربات یکپارچه آلفا (متصل به بله + دیتاست + سیستم ضد باگ) روشن است! 🚀"
194
+
195
+ def run_flask():
196
+ app.run(host="0.0.0.0", port=7860)
197
+
198
+
199
+ # --- ساختار کیبورد استاندارد بله/تلگرام ---
200
+ def get_main_keyboard():
201
+ markup = ReplyKeyboardMarkup(resize_keyboard=True)
202
+ markup.row(KeyboardButton("چت با هوش مصنوعی 🤖"))
203
+ markup.row(KeyboardButton("ساخت تصاویر🎨"), KeyboardButton("ویرایش تصاویر 🪄"))
204
+ markup.row(KeyboardButton("ساخت پادکست 🎙️"), KeyboardButton("تبدیل متن به صدا🗣️"))
205
+ markup.row(KeyboardButton("فایل صوتی به متن 📝"), KeyboardButton("تحلیل فایل 📁"))
206
+ markup.row(KeyboardButton("ساخت فایل 📄"))
207
+ markup.row(KeyboardButton("حساب کاربری 👤"), KeyboardButton("خرید اشتراک 💎"))
208
+ markup.row(KeyboardButton("انتقال اکانت از برنامه به ربات"))
209
+ markup.row(KeyboardButton("برگشت♻️"))
210
+ return markup
211
+
212
+ def get_join_keyboard():
213
+ markup = ReplyKeyboardMarkup(resize_keyboard=True)
214
+ markup.row(KeyboardButton("✅ عضو شدم"))
215
+ return markup
216
+
217
+ # --- ⛔️ سیستم بررسی عضویت اجباری کانال (Force Join) ⛔️ ---
218
+ CHANNEL_USERNAME = "aialpha"
219
+
220
+ async def check_channel_membership(client, user_id):
221
+ global BOT_GUID
222
+ if str(user_id) == str(BOT_GUID): return True
223
+ try:
224
+ member = await client.get_chat_member(f"@{CHANNEL_USERNAME}", user_id)
225
+ if member.status in ['member', 'administrator', 'creator']:
226
+ return True
227
+ return False
228
+ except Exception:
229
+ return False
230
+
231
+ # --- تابع ارسال منحصراً برای کیبورد پایین صفحه ---
232
+ async def send_with_keyboard(client, chat_id, text, use_keyboard=True):
233
+ try:
234
+ markup = get_main_keyboard() if use_keyboard else None
235
+ return await client.send_message(chat_id, text, reply_markup=markup)
236
+ except Exception:
237
+ try:
238
+ return await client.send_message(chat_id, text)
239
+ except Exception:
240
+ return None
241
+
242
+
243
+ # --- 🚨 تابع هوشمند دانلود فایل از بله ---
244
+ async def helper_download_file(client, message):
245
+ file_id = None
246
+ if message.document:
247
+ file_id = message.document.file_id
248
+ elif message.photo:
249
+ file_id = message.photo[-1].file_id
250
+ elif message.voice:
251
+ file_id = message.voice.file_id
252
+ elif message.audio:
253
+ file_id = message.audio.file_id
254
+ elif message.video:
255
+ file_id = message.video.file_id
256
+
257
+ if not file_id:
258
+ raise Exception("هیچ فایلی برای دانلود یافت نشد.")
259
+
260
+ file_info = await client.get_file(file_id)
261
+ downloaded_bytes = await client.download_file(file_info.file_path)
262
+ return downloaded_bytes
263
+
264
+
265
+ # --- تنظیمات کلیدها ---
266
+ GEMINI_KEYS_STR1 = os.environ.get("GEMINI_API_KEYS1", "")
267
+ GEMINI_KEYS_STR2 = os.environ.get("GEMINI_API_KEYS2", "")
268
+
269
+ _raw_keys =[]
270
+ if GEMINI_KEYS_STR1:
271
+ _raw_keys.extend(GEMINI_KEYS_STR1.split(","))
272
+ if GEMINI_KEYS_STR2:
273
+ _raw_keys.extend(GEMINI_KEYS_STR2.split(","))
274
+
275
+ GEMINI_KEYS = list(set([k.strip() for k in _raw_keys if k.strip()]))
276
+ print(f"✅ تعداد {len(GEMINI_KEYS)} کلید جیمینای با موفقیت شناسایی شد.")
277
+
278
+ current_gemini_key_index = 0
279
+ gemini_key_lock = threading.Lock()
280
+
281
+ def get_next_gemini_keys(count=100):
282
+ global current_gemini_key_index
283
+ with gemini_key_lock:
284
+ total_keys = len(GEMINI_KEYS)
285
+ if total_keys == 0:
286
+ return[]
287
+
288
+ actual_count = min(count, total_keys)
289
+ selected_keys =[]
290
+
291
+ for _ in range(actual_count):
292
+ selected_keys.append(GEMINI_KEYS[current_gemini_key_index])
293
+ current_gemini_key_index = (current_gemini_key_index + 1) % total_keys
294
+
295
+ return selected_keys
296
+
297
+ HF_TOKENS_STR = os.environ.get("HF_TOKENS", "")
298
+ HF_TOKENS =[k.strip() for k in HF_TOKENS_STR.split(",") if k.strip()]
299
+
300
+ # استفاده از توکن بله (BALE_TOKEN)
301
+ bot_token = os.environ.get("BALE_TOKEN", "").strip()
302
+
303
+
304
+ # --- 🚨 تابع اختصاصی آپلود فایل به بله ---
305
+ async def helper_upload_file(client, chat_id, file_name, file_type="Image", caption=""):
306
+ abs_path = os.path.abspath(file_name)
307
+ try:
308
+ with open(abs_path, "rb") as f:
309
+ markup = get_main_keyboard()
310
+ if file_type in["photo", "Image", "image"]:
311
+ await client.send_photo(chat_id, photo=f, caption=caption, reply_markup=markup)
312
+ elif file_type in ["voice", "Voice", "audio"]:
313
+ if abs_path.lower().endswith('.ogg'):
314
+ await client.send_voice(chat_id, voice=f, caption=caption, reply_markup=markup)
315
+ else:
316
+ await client.send_audio(chat_id, audio=f, caption=caption, reply_markup=markup)
317
+ elif file_type == "Music":
318
+ await client.send_audio(chat_id, audio=f, caption=caption, reply_markup=markup)
319
+ else:
320
+ await client.send_document(chat_id, document=f, caption=caption, reply_markup=markup)
321
+ return True
322
+ except Exception as e:
323
+ return f"Bale Send Error: {str(e)[:100]}"
324
+
325
+
326
+ WORKER_URLS =[
327
+ "https://opera8-ttspro.hf.space/generate",
328
+ ]
329
+
330
+ SPEAKERS = {
331
+ "1": ("شهاب (مرد)", "Charon"), "2": ("آوا (زن)", "Zephyr"), "3": ("نوید (مرد)", "Achird"),
332
+ "4": ("آرمان (مرد)", "Zubenelgenubi"), "5": ("مهسا (زن)", "Vindemiatrix"), "6": ("دانا (مرد)", "Rasalgethi"),
333
+ "7": ("سامان (مرد)", "Sadachbia"), "8": ("آرش (مرد)", "Sadaltager"), "9": ("شبنم (زن)", "Sulafat"),
334
+ "10": ("سحر (زن)", "Laomedeia"), "11": ("مریم (زن)", "Achernar"), "12": ("بهرام (مرد)", "Alnilam"),
335
+ "13": ("نیکان (مرد)", "Schedar"), "14": ("فرناز (زن)", "Gacrux"), "15": ("سارا (زن)", "Pulcherrima"),
336
+ "16": ("مانی (مرد)", "Umbriel"), "17": ("آرتین (مرد)", "Algieba"), "18": ("دلنواز (زن)", "Despina"),
337
+ "19": ("روژان (زن)", "Erinome"), "20": ("امید (مرد)", "Algenib"), "21": ("بردیا (مرد)", "Orus"),
338
+ "22": ("ترانه (زن)", "Aoede"), "23": ("نیکو (زن)", "Callirrhoe"), "24": ("هستی (زن)", "Autonoe"),
339
+ "25": ("کامیار (مرد)", "Enceladus"), "26": ("کیانوش (مرد)", "Iapetus"), "27": ("پویا (مرد)", "Puck"),
340
+ "28": ("مهتاب (زن)", "Kore"), "29": ("سام (مرد)", "Fenrir"), "30": ("لیدا (زن)", "Leda")
341
+ }
342
+
343
+ user_states = {}
344
+ processed_message_ids = set()
345
+ user_last_request_time = {}
346
+
347
+
348
+ # --- ۱. پردازش چت متنی و چندرسانه‌ای ---
349
+ async def process_gemini(client, chat_id, prompt, file_bytes=None, file_name=None):
350
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
351
+ creds = get_user_credits(str_chat_id)
352
+ if creds["chat"] <= 0:
353
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار پیام‌های چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
354
+
355
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای API جیمینای تنظیم نشده‌اند.", False)
356
+
357
+ proc_msg = await send_with_keyboard(client, chat_id, "🧠 در حال پردازش...", False)
358
+ history = user_states[chat_id].get("history",[])
359
+ new_parts =[]
360
+
361
+ if prompt: new_parts.append({"text": prompt})
362
+ elif file_bytes: new_parts.append({"text": "لطفاً این فایل را به دقت بررسی کن."})
363
+
364
+ if file_bytes and file_name:
365
+ base64_data = base64.b64encode(file_bytes).decode('utf-8')
366
+ mime_type, _ = mimetypes.guess_type(file_name)
367
+ if not mime_type:
368
+ if file_name.endswith(('.jpg', '.jpeg')): mime_type = "image/jpeg"
369
+ elif file_name.endswith('.png'): mime_type = "image/png"
370
+ elif file_name.endswith('.pdf'): mime_type = "application/pdf"
371
+ elif file_name.endswith('.mp4'): mime_type = "video/mp4"
372
+ elif file_name.endswith('.mp3'): mime_type = "audio/mp3"
373
+ elif file_name.endswith(('.ogg', '.oga')): mime_type = "audio/ogg"
374
+ elif file_name.endswith('.wav'): mime_type = "audio/wav"
375
+ else: mime_type = "image/jpeg"
376
+ new_parts.append({"inlineData": {"mimeType": mime_type, "data": base64_data}})
377
+
378
+ if history and history[-1]["role"] == "user": history[-1]["parts"].extend(new_parts)
379
+ else: history.append({"role": "user", "parts": new_parts})
380
+
381
+ if len(history) > 40:
382
+ history = history[-40:]
383
+ if history[0]["role"] == "model": history = history[1:]
384
+
385
+ keys_to_try = get_next_gemini_keys(100)
386
+ final_answer = None
387
+
388
+ async with aiohttp.ClientSession() as session:
389
+ for key in keys_to_try:
390
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
391
+ payload = {"contents": history, "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
392
+ try:
393
+ async with session.post(url, json=payload, timeout=60) as response:
394
+ if response.status == 200:
395
+ data = await response.json()
396
+ try:
397
+ final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
398
+ break
399
+ except (KeyError, IndexError): continue
400
+ except Exception: continue
401
+
402
+ # --- Fallback to Hugging Face Gemma 4 ---
403
+ if not final_answer and HF_TOKENS:
404
+ hf_messages =[]
405
+ for msg in history:
406
+ role = "assistant" if msg["role"] == "model" else "user"
407
+ content_parts =[]
408
+ for part in msg["parts"]:
409
+ if "text" in part:
410
+ content_parts.append({"type": "text", "text": part["text"]})
411
+ elif "inlineData" in part:
412
+ mime_t = part["inlineData"]["mimeType"]
413
+ b64_d = part["inlineData"]["data"]
414
+ content_parts.append({
415
+ "type": "image_url",
416
+ "image_url": {"url": f"data:{mime_t};base64,{b64_d}"}
417
+ })
418
+ hf_messages.append({"role": role, "content": content_parts})
419
+
420
+ keys_to_try_hf = HF_TOKENS.copy()
421
+ random.shuffle(keys_to_try_hf)
422
+
423
+ async with aiohttp.ClientSession() as session:
424
+ for hf_key in keys_to_try_hf:
425
+ url = "https://router.huggingface.co/v1/chat/completions"
426
+ headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
427
+ payload = {
428
+ "model": "google/gemma-4-31B-it:novita",
429
+ "messages": hf_messages,
430
+ "max_tokens": 4096
431
+ }
432
+ try:
433
+ async with session.post(url, headers=headers, json=payload, timeout=60) as response:
434
+ if response.status == 200:
435
+ data = await response.json()
436
+ final_answer = data["choices"][0]["message"]["content"]
437
+ break
438
+ except Exception:
439
+ continue
440
+
441
+ try:
442
+ if proc_msg:
443
+ msg_id = getattr(proc_msg, 'message_id', None)
444
+ if msg_id: await client.delete_message(chat_id, msg_id)
445
+ except Exception: pass
446
+
447
+ if not final_answer:
448
+ if history and history[-1]["role"] == "user": history.pop()
449
+ await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", False)
450
+ return
451
+
452
+ if not creds.get("is_premium"):
453
+ user_credits_db[str_chat_id]["chat"] -= 1
454
+ save_db(user_credits_db)
455
+
456
+ history.append({"role": "model", "parts":[{"text": final_answer}]})
457
+ user_states[chat_id]["history"] = history
458
+
459
+ try:
460
+ max_len = 1000
461
+ chunks =[]
462
+ temp_text = final_answer
463
+ while len(temp_text) > max_len:
464
+ split_idx = temp_text.rfind('\n', 0, max_len)
465
+ if split_idx == -1: split_idx = temp_text.rfind(' ', 0, max_len)
466
+ if split_idx == -1: split_idx = max_len
467
+ chunks.append(temp_text[:split_idx])
468
+ temp_text = temp_text[split_idx:].strip()
469
+ if temp_text: chunks.append(temp_text)
470
+
471
+ for idx, chunk in enumerate(chunks):
472
+ if idx != len(chunks) - 1: chunk += "\n\n⏳ *(ادامه در پیام بعدی)...* 👇"
473
+ try:
474
+ await send_with_keyboard(client, chat_id, chunk, False)
475
+ await asyncio.sleep(2.5)
476
+ except Exception: await asyncio.sleep(2.5)
477
+
478
+ except Exception:
479
+ await send_with_keyboard(client, chat_id, "❌ خطایی در ارسال پیام رخ داد.", False)
480
+
481
+
482
+ # --- ۲. پردازش ساخت عکس ---
483
+ async def process_image(client, chat_id, prompt):
484
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
485
+ creds = get_user_credits(str_chat_id)
486
+ if creds["image"] <= 0:
487
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت عکس شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
488
+
489
+ if not HF_TOKENS: return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
490
+
491
+ proc_msg = await send_with_keyboard(client, chat_id, "✨ در حال ترجمه و بهینه‌سازی پرامپت شما...\n(تبدیل به پرامپت حرفه‌ای)", False)
492
+ enhanced_prompt = prompt
493
+ 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}"
494
+
495
+ if GEMINI_KEYS:
496
+ keys_to_try_gemini = get_next_gemini_keys(100)
497
+ async with aiohttp.ClientSession() as session:
498
+ for key in keys_to_try_gemini:
499
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
500
+ payload = {"contents": [{"parts":[{"text": gemini_sys_prompt}]}], "generationConfig": {"temperature": 0.7}}
501
+ try:
502
+ async with session.post(url, json=payload, timeout=20) as response:
503
+ if response.status == 200:
504
+ data = await response.json()
505
+ enhanced_prompt = data["candidates"][0]["content"]["parts"][0]["text"].strip()
506
+ break
507
+ except Exception: continue
508
+
509
+ if enhanced_prompt == prompt and HF_TOKENS:
510
+ keys_to_try_hf = HF_TOKENS.copy()
511
+ random.shuffle(keys_to_try_hf)
512
+ async with aiohttp.ClientSession() as session:
513
+ for hf_key in keys_to_try_hf:
514
+ url = "https://router.huggingface.co/v1/chat/completions"
515
+ headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
516
+ payload = {
517
+ "model": "google/gemma-4-31B-it:novita",
518
+ "messages":[{"role": "user", "content":[{"type": "text", "text": gemini_sys_prompt}]}],
519
+ "max_tokens": 1024
520
+ }
521
+ try:
522
+ async with session.post(url, headers=headers, json=payload, timeout=20) as response:
523
+ if response.status == 200:
524
+ data = await response.json()
525
+ enhanced_prompt = data["choices"][0]["message"]["content"].strip()
526
+ break
527
+ except Exception:
528
+ continue
529
+
530
+ try:
531
+ if proc_msg:
532
+ msg_id = getattr(proc_msg, 'message_id', None)
533
+ if msg_id: await client.delete_message(chat_id, msg_id)
534
+ except Exception: pass
535
+
536
+ short_preview = enhanced_prompt[:150] + "..." if len(enhanced_prompt) > 150 else enhanced_prompt
537
+ proc_msg = await send_with_keyboard(client, chat_id, f"🎨 در حال طراحی عکس...\n\n📝 پرامپت ساخته شده:\n`{short_preview}`\n\n(ممکن است چند ثانیه زمان ببرد)", False)
538
+
539
+ keys_to_try = HF_TOKENS.copy()
540
+ random.shuffle(keys_to_try)
541
+ generated_image = None
542
+ last_error_log = "هیچ اتصالی برقرار نشد."
543
+
544
+ for token in keys_to_try:
545
+ try:
546
+ hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
547
+ generated_image = await hf_client.text_to_image(enhanced_prompt, model="Tongyi-MAI/Z-Image-Turbo")
548
+ break
549
+ except Exception as e:
550
+ last_error_log = str(e)
551
+ continue
552
+
553
+ try:
554
+ if proc_msg:
555
+ msg_id = getattr(proc_msg, 'message_id', None)
556
+ if msg_id: await client.delete_message(chat_id, msg_id)
557
+ except Exception: pass
558
+
559
+ if not generated_image: return await send_with_keyboard(client, chat_id, f"❌ عکس ساخته نشد.\n\n⚠️ خطا:\n{last_error_log[:200]}", True)
560
+
561
+ user_credits_db[str_chat_id]["image"] -= 1
562
+ save_db(user_credits_db)
563
+
564
+ try:
565
+ file_name = f"image_{uuid.uuid4().hex}.jpg"
566
+ rgb_im = generated_image.convert('RGB')
567
+ rgb_im.save(file_name, format="JPEG", quality=100)
568
+ await asyncio.sleep(1)
569
+ caption_text = f"🎨 تصویر شما با پرامپت هوشمند آماده شد!\n\n✨ ایده اولیه: {prompt}"
570
+ upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
571
+ if upload_result is not True: await send_with_keyboard(client, chat_id, f"❌ خطا در آپلود بله:\n`{str(upload_result)[:800]}`", True)
572
+ if os.path.exists(file_name): os.remove(file_name)
573
+ except Exception as e: await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس:\n{str(e)[:150]}", True)
574
+
575
+ async def translate_text_aloha(prompt_text):
576
+ session_hash = ''.join(random.choices(string.ascii_lowercase + string.digits, k=11))
577
+ join_url = "https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/join"
578
+ payload = {
579
+ "data":[prompt_text, "انگلیسی (آمریکا) - جنی (زن)", 0, 0, 0],
580
+ "fn_index": 1,
581
+ "session_hash": session_hash
582
+ }
583
+
584
+ try:
585
+ async with aiohttp.ClientSession() as session:
586
+ async with session.post(join_url, json=payload, timeout=20) as resp:
587
+ if resp.status != 200:
588
+ return prompt_text
589
+
590
+ data_url = f"https://hamed744-translate-tts-aloha.hf.space/gradio_api/queue/data?session_hash={session_hash}"
591
+ async with session.get(data_url, timeout=60) as resp:
592
+ async for line_bytes in resp.content:
593
+ line = line_bytes.decode('utf-8').strip()
594
+ if line.startswith("data: "):
595
+ try:
596
+ json_data = json.loads(line[6:])
597
+ if json_data.get("msg") == "process_completed":
598
+ if json_data.get("success"):
599
+ return json_data["output"]["data"][0]
600
+ break
601
+ except Exception:
602
+ pass
603
+ except Exception:
604
+ pass
605
+
606
+ return prompt_text
607
+
608
+ # --- ۲.۵. پردازش ویرایش عکس ---
609
+ async def process_image_edit(client, chat_id, image_bytes, prompt):
610
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
611
+ creds = get_user_credits(str_chat_id)
612
+ if creds["edit_image"] <= 0:
613
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار ویرایش عکس شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
614
+
615
+ if not HF_TOKENS:
616
+ return await send_with_keyboard(client, chat_id, "❌ توکن‌های هاگینگ فیس تنظیم نشده‌اند.", False)
617
+
618
+ proc_msg = await send_with_keyboard(client, chat_id, "🪄 در حال ترجمه دستور شما توسط اسپیس و اعمال جادوی FLUX.2...\n(این فرآیند ممکن است کمی طول بکشد)", False)
619
+
620
+ translated_prompt = await translate_text_aloha(prompt)
621
+ if not translated_prompt or translated_prompt.strip() == "":
622
+ translated_prompt = prompt
623
+
624
+ keys_to_try = HF_TOKENS.copy()
625
+ random.shuffle(keys_to_try)
626
+ generated_image = None
627
+ last_error_log = "سرور پاسخ نداد."
628
+
629
+ for token in keys_to_try:
630
+ try:
631
+ hf_client = AsyncInferenceClient(provider="fal-ai", api_key=token)
632
+ generated_image = await hf_client.image_to_image(
633
+ image_bytes,
634
+ prompt=translated_prompt,
635
+ model="black-forest-labs/FLUX.2-dev"
636
+ )
637
+ break
638
+ except Exception as e:
639
+ last_error_log = str(e)
640
+ continue
641
+
642
+ try:
643
+ if proc_msg:
644
+ msg_id = getattr(proc_msg, 'message_id', None)
645
+ if msg_id: await client.delete_message(chat_id, msg_id)
646
+ except Exception: pass
647
+
648
+ if not generated_image:
649
+ return await send_with_keyboard(client, chat_id, f"❌ متأسفانه ویرایش عکس انجام نشد.\n\n⚠️ علت:\n{last_error_log[:200]}", True)
650
+
651
+ user_credits_db[str_chat_id]["edit_image"] -= 1
652
+ save_db(user_credits_db)
653
+
654
+ try:
655
+ file_name = f"edited_flux_{uuid.uuid4().hex}.jpg"
656
+ rgb_im = generated_image.convert('RGB')
657
+ rgb_im.save(file_name, format="JPEG", quality=100)
658
+ await asyncio.sleep(1)
659
+ caption_text = f"🪄 ویرایش عکس با هوش مصنوعی Flux.2 انجام شد!\n\n✨ تغییرات خواسته شده: {prompt}\n🔤 متن ارسال شده به هوش: {translated_prompt}"
660
+ upload_result = await helper_upload_file(client, chat_id, file_name, "Image", caption_text)
661
+ if upload_result is not True:
662
+ await send_with_keyboard(client, chat_id, f"❌ عکس ساخته شد اما خطا در ارسال به بله رخ داد:\n`{str(upload_result)[:800]}`", True)
663
+ if os.path.exists(file_name): os.remove(file_name)
664
+ except Exception as e:
665
+ await send_with_keyboard(client, chat_id, f"❌ خطا در ذخیره عکس ویرایش شده:\n{str(e)[:150]}", True)
666
+
667
+
668
+ # --- ۳. پردازش ساخت صدا ---
669
+ async def process_tts(client, chat_id, user_text, speaker_id, speaker_name):
670
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
671
+ creds = get_user_credits(str_chat_id)
672
+ if creds["tts"] <= 0:
673
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل متن به صدای شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
674
+
675
+ try:
676
+ proc_msg = await send_with_keyboard(client, chat_id, f"⏳ در حال ساخت صدا با «{speaker_name}»...\n(لطفاً صبور باشید)", False)
677
+ payload = {"text": user_text, "speaker": speaker_id, "temperature": 1.5, "prompt": "", "use_live_model": True}
678
+ headers = {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"}
679
+ audio_bytes = None
680
+ last_error = "پاسخی دریافت نشد"
681
+ workers = WORKER_URLS.copy()
682
+ random.shuffle(workers)
683
+
684
+ async with aiohttp.ClientSession(headers=headers, timeout=aiohttp.ClientTimeout(total=600)) as session:
685
+ for worker_url in workers[:3]:
686
+ try:
687
+ async with session.post(worker_url, json=payload) as response:
688
+ if response.status == 200:
689
+ content_type = response.headers.get('Content-Type', '')
690
+ if 'audio' in content_type or response.content_length > 1000:
691
+ audio_bytes = await response.read()
692
+ break
693
+ else: last_error = "فایل نامعتبر"
694
+ else: last_error = f"ارور ({response.status})"
695
+ except Exception as e: last_error = f"خطا: {str(e)}"; continue
696
+
697
+ try:
698
+ if proc_msg:
699
+ msg_id = getattr(proc_msg, 'message_id', None)
700
+ if msg_id: await client.delete_message(chat_id, msg_id)
701
+ except Exception: pass
702
+
703
+ if audio_bytes:
704
+ if not creds.get("is_premium"):
705
+ user_credits_db[str_chat_id]["tts"] -= 1
706
+ save_db(user_credits_db)
707
+
708
+ file_name_mp3 = f"audio_{uuid.uuid4().hex}.mp3"
709
+
710
+ with open(file_name_mp3, "wb") as f: f.write(audio_bytes)
711
+
712
+ await asyncio.sleep(1)
713
+
714
+ upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", "✅ صدای شما با موفقیت آماده شد (فایل MP3):")
715
+
716
+ if upload_result_file is not True:
717
+ await send_with_keyboard(client, chat_id, f"❌ ارور آپلود فایل:\n`{str(upload_result_file)[:800]}`", True)
718
+
719
+ if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
720
+ else: await send_with_keyboard(client, chat_id, f"❌ سرورها درگیر هستند.\nدلیل: {last_error}", True)
721
+ except Exception: traceback.print_exc()
722
+
723
+
724
+ # --- ۳.۵. پردازش پادکست ---
725
+ async def process_podcast(client, chat_id, prompt):
726
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
727
+ creds = get_user_credits(str_chat_id)
728
+ if creds["podcast"] <= 0:
729
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار ساخت پادکست شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
730
+
731
+ proc_msg = await send_with_keyboard(client, chat_id, "📻 در حال بررسی موضوع و نگارش سناریوی پادکست توسط هوش مصنوعی...\n(لطفاً صبور باشید)", False)
732
+ available_speakers =[]
733
+ for num_key, (spk_name, spk_id) in SPEAKERS.items():
734
+ gender = "male" if "مرد" in spk_name else "female"
735
+ available_speakers.append({"id": spk_id, "name": spk_name.split(' (')[0], "gender": gender})
736
+
737
+ url_create = "https://opera8-podgen.hf.space/api/create-full-podcast"
738
+ payload_create = {"prompt": prompt, "available_speakers": available_speakers}
739
+
740
+ async with aiohttp.ClientSession() as session:
741
+ try:
742
+ async with session.post(url_create, json=payload_create, timeout=60) as resp:
743
+ if resp.status != 202: return await send_with_keyboard(client, chat_id, f"❌ خطا در سرور پادکست: وضعیت {resp.status}", True)
744
+ task_id = (await resp.json()).get("task_id")
745
+ except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در اتصال به سرور پادکست:\n{str(e)}", True)
746
+
747
+ url_status = f"https://opera8-podgen.hf.space/api/podcast-status/{task_id}"
748
+ script_data = None
749
+ for _ in range(500):
750
+ await asyncio.sleep(3)
751
+ try:
752
+ async with session.get(url_status) as resp:
753
+ if resp.status == 200:
754
+ status_data = await resp.json()
755
+ if status_data.get("status") == "completed":
756
+ script_data = status_data.get("data", {}).get("script",[])
757
+ break
758
+ elif status_data.get("status") == "failed":
759
+ return await send_with_keyboard(client, chat_id, "❌ متأسفانه هوش مصنوعی ��توانست برای این موضوع سناریو بنویسد.", True)
760
+ except Exception: pass
761
+
762
+ if not script_data: return await send_with_keyboard(client, chat_id, "❌ زمان انتظار برای نوشتن سناریو به پایان رسید.", True)
763
+
764
+ try:
765
+ if proc_msg:
766
+ msg_id = getattr(proc_msg, 'message_id', None)
767
+ if msg_id: await client.delete_message(chat_id, msg_id)
768
+ except: pass
769
+
770
+ proc_msg = await send_with_keyboard(client, chat_id, f"🎙 سناریو نوشته شد! در حال ریکورد و میکس دیالوگ‌های گویندگان (شامل {len(script_data)} نوبت صحبت)...\nاین مرحله زمان‌بر است...", False)
771
+
772
+ combined_audio = AudioSegment.empty()
773
+ url_generate = "https://opera8-podgen.hf.space/api/generate"
774
+
775
+ for index, turn in enumerate(script_data):
776
+ payload_gen = {"text": turn["dialogue"], "speaker": turn["speaker_id"], "temperature": 0.9}
777
+ chunk_audio_bytes = None
778
+ for attempt in range(3):
779
+ try:
780
+ async with session.post(url_generate, json=payload_gen, timeout=120) as resp:
781
+ if resp.status == 200:
782
+ chunk_audio_bytes = await resp.read()
783
+ break
784
+ except Exception: await asyncio.sleep(2)
785
+
786
+ if not chunk_audio_bytes: return await send_with_keyboard(client, chat_id, f"❌ خطا در تولید صدای بخش {index+1} از سرور. عملیات متوقف شد.", True)
787
+
788
+ try:
789
+ audio_segment = AudioSegment.from_file(io.BytesIO(chunk_audio_bytes))
790
+ combined_audio += audio_segment
791
+ except Exception as e: return await send_with_keyboard(client, chat_id, f"❌ خطا در پردازش صدا:\n{str(e)}", True)
792
+
793
+ if not creds.get("is_premium"):
794
+ user_credits_db[str_chat_id]["podcast"] -= 1
795
+ save_db(user_credits_db)
796
+
797
+ file_name_mp3 = f"final_podcast_{uuid.uuid4().hex}.mp3"
798
+ combined_audio.export(file_name_mp3, format="mp3")
799
+
800
+ try:
801
+ if proc_msg:
802
+ msg_id = getattr(proc_msg, 'message_id', None)
803
+ if msg_id: await client.delete_message(chat_id, msg_id)
804
+ except: pass
805
+
806
+ caption_file = f"🎧 فایل پادکست شما با فرمت MP3:\n\n💡 موضوع شما: {prompt}"
807
+
808
+ upload_result_file = await helper_upload_file(client, chat_id, file_name_mp3, "File", caption_file)
809
+
810
+ if upload_result_file is not True:
811
+ await send_with_keyboard(client, chat_id, f"❌ پادکست ساخته شد اما بله خطای آپلود داد.\n\n`{str(upload_result_file)[:800]}`", True)
812
+
813
+ if os.path.exists(file_name_mp3): os.remove(file_name_mp3)
814
+
815
+
816
+ # --- ۴. پردازش تبدیل فایل صوتی/تصویری به متن ---
817
+ async def process_stt(client, chat_id, audio_bytes, file_name):
818
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
819
+ creds = get_user_credits(str_chat_id)
820
+ if creds["stt"] <= 0:
821
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار تبدیل صدا به متن شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
822
+
823
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
824
+
825
+ proc_msg = await send_with_keyboard(client, chat_id, "📝 در حال گوش دادن و پیاده‌سازی متن...", False)
826
+ base64_data = base64.b64encode(audio_bytes).decode('utf-8')
827
+ mime_type, _ = mimetypes.guess_type(file_name)
828
+ if not mime_type: mime_type = "audio/ogg"
829
+
830
+ keys_to_try = get_next_gemini_keys(100)
831
+ transcribed_text = None
832
+ prompt = "لطفاً این فایل صوتی/تصویری را با دقت کامل گوش بده و صحبت‌های داخل آن را کلمه به کلمه به متن تبدیل کن. هیچ توضیح اضافه‌ای نده."
833
+
834
+ async with aiohttp.ClientSession() as session:
835
+ for key in keys_to_try:
836
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
837
+ payload = {"contents": [{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.2}}
838
+ try:
839
+ async with session.post(url, json=payload, timeout=60) as response:
840
+ if response.status == 200:
841
+ data = await response.json()
842
+ transcribed_text = data["candidates"][0]["content"]["parts"][0]["text"]
843
+ break
844
+ except Exception: continue
845
+
846
+ try:
847
+ if proc_msg:
848
+ msg_id = getattr(proc_msg, 'message_id', None)
849
+ if msg_id: await client.delete_message(chat_id, msg_id)
850
+ except Exception: pass
851
+
852
+ if transcribed_text:
853
+ if not creds.get("is_premium"):
854
+ user_credits_db[str_chat_id]["stt"] -= 1
855
+ save_db(user_credits_db)
856
+ await send_with_keyboard(client, chat_id, f"📝 **متن استخراج شده:**\n\n{transcribed_text}", True)
857
+ else:
858
+ await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
859
+
860
+
861
+ # --- ۵. پردازش تحلیل فایل مستقل ---
862
+ async def process_file_analysis(client, chat_id, file_bytes, file_name, prompt):
863
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
864
+ creds = get_user_credits(str_chat_id)
865
+ if creds["file"] <= 0:
866
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار تحلیل فایل شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
867
+
868
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلید جیمینای تنظیم نیست.", False)
869
+
870
+ proc_msg = await send_with_keyboard(client, chat_id, "👁️ در حال تحلیل فایل...", False)
871
+ base64_data = base64.b64encode(file_bytes).decode('utf-8')
872
+ mime_type, _ = mimetypes.guess_type(file_name)
873
+ if not mime_type: mime_type = "image/jpeg"
874
+
875
+ keys_to_try = get_next_gemini_keys(100)
876
+ final_answer = None
877
+
878
+ async with aiohttp.ClientSession() as session:
879
+ for key in keys_to_try:
880
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
881
+ payload = {"contents":[{"parts":[{"text": prompt}, {"inlineData": {"mimeType": mime_type, "data": base64_data}}]}], "generationConfig": {"temperature": 0.6}}
882
+ try:
883
+ async with session.post(url, json=payload, timeout=45) as response:
884
+ if response.status == 200:
885
+ data = await response.json()
886
+ final_answer = data["candidates"][0]["content"]["parts"][0]["text"]
887
+ break
888
+ except Exception: continue
889
+
890
+ try:
891
+ if proc_msg:
892
+ msg_id = getattr(proc_msg, 'message_id', None)
893
+ if msg_id: await client.delete_message(chat_id, msg_id)
894
+ except Exception: pass
895
+
896
+ if final_answer:
897
+ if not creds.get("is_premium"):
898
+ user_credits_db[str_chat_id]["file"] -= 1
899
+ save_db(user_credits_db)
900
+ await send_with_keyboard(client, chat_id, f"💡 **نتیجه تحلیل:**\n\n{final_answer}", True)
901
+ else:
902
+ await send_with_keyboard(client, chat_id, "❌ سرور شلوغ است فعلا بعدا امتحان کنید.", True)
903
+
904
+
905
+ # --- ۵.۵. پردازش ساخت مقاله و تبدیل به فایل ---
906
+ async def process_create_file(client, chat_id, topic):
907
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
908
+ creds = get_user_credits(str_chat_id)
909
+
910
+ if creds["chat"] <= 0:
911
+ return await send_with_keyboard(client, chat_id, "❌ اعتبار چت شما تمام شده است. لطفاً از منوی اصلی وارد بخش «خرید اشتراک 💎» شوید.", False)
912
+
913
+ if not GEMINI_KEYS: return await send_with_keyboard(client, chat_id, "❌ کلیدهای جیمینای تنظیم نشده‌اند.", False)
914
+
915
+ proc_msg = await send_with_keyboard(client, chat_id, "✍️ در حال تحقیق و نگارش مقاله جامع و حرفه‌ای...\n(این عملیات با توجه به طولانی بودن متن ممکن است کمی طول بکشد)", False)
916
+
917
+ ai_prompt = f"یک مقاله بسیار جامع، کاملا حرفه‌ای، بسیار طولانی و با جزئیات کامل درباره موضوع زیر به زبان فارسی بنویس. فقط متن مقاله را بده و هیچ توضیح اضافه‌ای نده:\n\nموضوع: {topic}"
918
+ article_text = None
919
+
920
+ keys_to_try = get_next_gemini_keys(100)
921
+ async with aiohttp.ClientSession() as session:
922
+ for key in keys_to_try:
923
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={key}"
924
+ payload = {"contents": [{"parts":[{"text": ai_prompt}]}], "generationConfig": {"temperature": 0.7, "maxOutputTokens": 8192}}
925
+ try:
926
+ async with session.post(url, json=payload, timeout=60) as response:
927
+ if response.status == 200:
928
+ data = await response.json()
929
+ article_text = data["candidates"][0]["content"]["parts"][0]["text"]
930
+ break
931
+ except Exception: continue
932
+
933
+ if not article_text and HF_TOKENS:
934
+ keys_to_try_hf = HF_TOKENS.copy()
935
+ random.shuffle(keys_to_try_hf)
936
+ async with aiohttp.ClientSession() as session:
937
+ for hf_key in keys_to_try_hf:
938
+ url = "https://router.huggingface.co/v1/chat/completions"
939
+ headers = {"Authorization": f"Bearer {hf_key}", "Content-Type": "application/json"}
940
+ payload = {
941
+ "model": "google/gemma-4-31B-it:novita",
942
+ "messages":[{"role": "user", "content":[{"type": "text", "text": ai_prompt}]}],
943
+ "max_tokens": 4096
944
+ }
945
+ try:
946
+ async with session.post(url, headers=headers, json=payload, timeout=60) as response:
947
+ if response.status == 200:
948
+ data = await response.json()
949
+ article_text = data["choices"][0]["message"]["content"]
950
+ break
951
+ except Exception: continue
952
+
953
+ if not article_text:
954
+ return await send_with_keyboard(client, chat_id, "❌ سرور تولید متن شلوغ است، لطفاً بعداً تلاش کنید.", True)
955
+
956
+ try:
957
+ if proc_msg:
958
+ msg_id = getattr(proc_msg, 'message_id', None)
959
+ if msg_id: await client.delete_message(chat_id, msg_id)
960
+ except Exception: pass
961
+
962
+ proc_msg = await send_with_keyboard(client, chat_id, "📄 مقاله با موفقیت نوشته شد! در حال ارتباط با سرور و تبدیل به فایل‌های PDF و Word...\n(لطفا صبور باشید)", False)
963
+
964
+ pdf_bytes = None
965
+ docx_bytes = None
966
+ converter_url = "https://opera8-texttopdf.hf.space/"
967
+
968
+ async with aiohttp.ClientSession() as session:
969
+ try:
970
+ form_data_pdf = aiohttp.FormData()
971
+ form_data_pdf.add_field('content', article_text)
972
+ form_data_pdf.add_field('format', 'pdf')
973
+ async with session.post(converter_url, data=form_data_pdf, timeout=60) as resp:
974
+ if resp.status == 200:
975
+ pdf_bytes = await resp.read()
976
+ except Exception as e: print("PDF creation error:", e)
977
+
978
+ try:
979
+ form_data_docx = aiohttp.FormData()
980
+ form_data_docx.add_field('content', article_text)
981
+ form_data_docx.add_field('format', 'docx')
982
+ async with session.post(converter_url, data=form_data_docx, timeout=60) as resp:
983
+ if resp.status == 200:
984
+ docx_bytes = await resp.read()
985
+ except Exception as e: print("DOCX creation error:", e)
986
+
987
+ try:
988
+ if proc_msg:
989
+ msg_id = getattr(proc_msg, 'message_id', None)
990
+ if msg_id: await client.delete_message(chat_id, msg_id)
991
+ except Exception: pass
992
+
993
+ if not pdf_bytes and not docx_bytes:
994
+ return await send_with_keyboard(client, chat_id, "❌ متاسفانه در تبدیل متن به فایل خطایی رخ داد.", True)
995
+
996
+ if not creds.get("is_premium"):
997
+ user_credits_db[str_chat_id]["chat"] -= 1
998
+ save_db(user_credits_db)
999
+
1000
+ uid = uuid.uuid4().hex
1001
+ pdf_filename = f"Article_{uid}.pdf"
1002
+ docx_filename = f"Article_{uid}.docx"
1003
+
1004
+ uploaded_any = False
1005
+
1006
+ if pdf_bytes:
1007
+ with open(pdf_filename, "wb") as f:
1008
+ f.write(pdf_bytes)
1009
+ res = await helper_upload_file(client, chat_id, pdf_filename, "File", f"📄 فایل PDF مقاله شما:\n\n💡 موضوع: {topic}")
1010
+ if res is True: uploaded_any = True
1011
+ if os.path.exists(pdf_filename): os.remove(pdf_filename)
1012
+ await asyncio.sleep(1.5)
1013
+
1014
+ if docx_bytes:
1015
+ with open(docx_filename, "wb") as f:
1016
+ f.write(docx_bytes)
1017
+ res = await helper_upload_file(client, chat_id, docx_filename, "File", f"📝 فایل Word (DOCX) مقاله شما:\n\n💡 موضوع: {topic}")
1018
+ if res is True: uploaded_any = True
1019
+ if os.path.exists(docx_filename): os.remove(docx_filename)
1020
+
1021
+ if uploaded_any:
1022
+ await send_with_keyboard(client, chat_id, "✅ مقاله شما با موفقیت به صورت فایل تحویل داده شد!", True)
1023
+ else:
1024
+ await send_with_keyboard(client, chat_id, "❌ فایل‌ها ساخته شدند اما بله در ارسال آن‌ها دچار مشکل شد.", True)
1025
+
1026
+
1027
+ # --- راه‌اندازی و اتصال هندلرها به بله ---
1028
+ bot = AsyncTeleBot(bot_token) if bot_token else None
1029
+
1030
+ if bot:
1031
+ @bot.message_handler(func=lambda message: True, content_types=['text', 'photo', 'document', 'voice', 'audio', 'video'])
1032
+ async def main_handler(message):
1033
+ global BOT_GUID
1034
+
1035
+ if is_backlog_burst():
1036
+ return
1037
+
1038
+ try:
1039
+ if not BOT_GUID:
1040
+ try:
1041
+ me_info = await bot.get_me()
1042
+ if me_info:
1043
+ BOT_GUID = me_info.id
1044
+ except Exception:
1045
+ pass
1046
+
1047
+ author_id = message.from_user.id
1048
+ if BOT_GUID and author_id == BOT_GUID:
1049
+ return
1050
+
1051
+ chat_id = message.chat.id
1052
+ msg_id = message.message_id
1053
+
1054
+ unique_msg_key = f"{chat_id}_{msg_id}" if msg_id else None
1055
+ if unique_msg_key:
1056
+ if unique_msg_key in processed_message_ids: return
1057
+ processed_message_ids.add(unique_msg_key)
1058
+ if len(processed_message_ids) > 5000: processed_message_ids.clear()
1059
+
1060
+ current_time = time.time()
1061
+ last_req_time = user_last_request_time.get(chat_id, 0)
1062
+ if current_time - last_req_time < 1.0:
1063
+ return
1064
+ user_last_request_time[chat_id] = current_time
1065
+
1066
+ user_text = message.text or message.caption or ""
1067
+ user_text_str = str(user_text).strip() if user_text else ""
1068
+ user_text_lower = user_text_str.lower()
1069
+
1070
+ if chat_id not in user_states:
1071
+ user_states[chat_id] = {"mode": None, "text": "", "history":[], "file_bytes": None, "file_name": None}
1072
+
1073
+ # 🛠 --- سیستم پنل مدیریت (بدون نیاز به لاگین) --- 🛠
1074
+ if user_text_lower.startswith(f"{ADMIN_CODE} pro=") or user_text_lower.startswith(f"{ADMIN_CODE}pro="):
1075
+ parts = user_text_str.split("=", 1)
1076
+ if len(parts) >= 2:
1077
+ target_id = parts[1].replace("`", "").replace("'", "").replace('"', "").strip()
1078
+ if target_id:
1079
+ if target_id not in user_credits_db:
1080
+ user_credits_db[target_id] = {
1081
+ "is_premium": False,
1082
+ "expire_date": None,
1083
+ "last_reset": "",
1084
+ "chat": 10,
1085
+ "image": 5,
1086
+ "edit_image": 1,
1087
+ "podcast": 2,
1088
+ "tts": 5,
1089
+ "file": 1,
1090
+ "stt": 5,
1091
+ "has_joined": True
1092
+ }
1093
+
1094
+ user_credits_db[target_id]["is_premium"] = True
1095
+ expire_time = datetime.datetime.now() + datetime.timedelta(days=30)
1096
+ user_credits_db[target_id]["expire_date"] = expire_time.isoformat()
1097
+
1098
+ user_credits_db[target_id]["chat"] = 999999
1099
+ user_credits_db[target_id]["image"] = 20
1100
+ user_credits_db[target_id]["edit_image"] = 10
1101
+ user_credits_db[target_id]["podcast"] = 999999
1102
+ user_credits_db[target_id]["tts"] = 999999
1103
+ user_credits_db[target_id]["file"] = 999999
1104
+ user_credits_db[target_id]["stt"] = 999999
1105
+
1106
+ save_db(user_credits_db)
1107
+ await send_with_keyboard(bot, chat_id, f"✅ حساب کاربر `{target_id}` به مدت ۳۰ روز شارژ شد و به پرو ارتقا یافت.", False)
1108
+ try:
1109
+ await send_with_keyboard(bot, target_id, "🎉 **کاربر گرامی، تبریک!**\n\nحساب شما با موفقیت توسط پشتیبانی به **🌟 نسخه پرو (ویژه)** ارتقا یافت.\nهم‌اکنون بسته‌های نامحدود و طلایی یک‌ماهه شما فعال گردید.\n\nجهت مشاهده جزئیات روی دکمه «حساب کاربری 👤» کلیک کنید.", True)
1110
+ except Exception: pass
1111
+ return
1112
+
1113
+ if user_text_lower.startswith(f"{ADMIN_CODE} free=") or user_text_lower.startswith(f"{ADMIN_CODE}free="):
1114
+ parts = user_text_str.split("=", 1)
1115
+ if len(parts) >= 2:
1116
+ target_id = parts[1].replace("`", "").replace("'", "").replace('"', "").strip()
1117
+ if target_id:
1118
+ if target_id in user_credits_db:
1119
+ user_credits_db[target_id]["is_premium"] = False
1120
+ user_credits_db[target_id]["expire_date"] = None
1121
+ user_credits_db[target_id]["last_reset"] = ""
1122
+ save_db(user_credits_db)
1123
+ await send_with_keyboard(bot, chat_id, f"✅ اشتراک کاربر `{target_id}` لغو شد و به رایگان تبدیل گشت.", False)
1124
+ try:
1125
+ await send_with_keyboard(bot, target_id, "⚠️ کاربر گرامی، اشتراک ویژه شما به پایان رسید و حساب شما به نسخه رایگان (آزمایشی) تغییر یافت.", True)
1126
+ except Exception: pass
1127
+ return
1128
+
1129
+ if user_text_lower.startswith(f"{ADMIN_CODE} =") or user_text_lower.startswith(f"{ADMIN_CODE}="):
1130
+ parts = user_text_str.split("=", 1)
1131
+ if len(parts) >= 2:
1132
+ target_id = parts[1].replace("`", "").replace("'", "").replace('"', "").strip()
1133
+ if target_id:
1134
+ if target_id in user_credits_db:
1135
+ t_creds = user_credits_db[target_id]
1136
+ is_prem = t_creds.get("is_premium", False)
1137
+
1138
+ if is_prem:
1139
+ expire_txt = "نامشخص"
1140
+ days_left = 0
1141
+ if t_creds.get("expire_date"):
1142
+ exp_d = datetime.datetime.fromisoformat(t_creds["expire_date"])
1143
+ now = datetime.datetime.now()
1144
+ diff = exp_d - now
1145
+ days_left = diff.days if diff.days >= 0 else 0
1146
+
1147
+ jy, jm, jd = gregorian_to_jalali(exp_d.year, exp_d.month, exp_d.day)
1148
+ expire_txt = f"{jy:04d}/{jm:02d}/{jd:02d}"
1149
+ status_text = f"🌟 نسخه پرو (ویژه)\n📅 انقضا: {expire_txt}\n⏳ باقیمانده: {days_left} روز"
1150
+ else:
1151
+ status_text = "🥉 نسخه رایگان (آزمایشی)\n⏳ سهمیه روزانه"
1152
+
1153
+ chat_rem = "نامحدود ∞" if is_prem else t_creds.get('chat', 0)
1154
+ podcast_rem = "نامحدود ∞" if is_prem else t_creds.get('podcast', 0)
1155
+ tts_rem = "نامحدود ∞" if is_prem else t_creds.get('tts', 0)
1156
+ file_rem = "نامحدود ∞" if is_prem else t_creds.get('file', 0)
1157
+ stt_rem = "نامحدود ∞" if is_prem else t_creds.get('stt', 0)
1158
+ image_rem = t_creds.get('image', 0)
1159
+ edit_image_rem = t_creds.get('edit_image', 0)
1160
+
1161
+ info_msg = f"""🔍 **اطلاعات کاربر `{target_id}`:**
1162
+
1163
+ 🔹 **وضعیت:** {status_text}
1164
+
1165
+ 📊 **سهمیه:**
1166
+ - چت: {chat_rem}
1167
+ - تولید عکس: {image_rem}
1168
+ - ویرایش عکس: {edit_image_rem}
1169
+ - پادکست: {podcast_rem}
1170
+ - متن به صدا: {tts_rem}
1171
+ - تحلیل فایل: {file_rem}
1172
+ - صدا به متن: {stt_rem}"""
1173
+ await send_with_keyboard(bot, chat_id, info_msg, False)
1174
+ else:
1175
+ await send_with_keyboard(bot, chat_id, f"❌ کاربری با شناسه `{target_id}` در دیتابیس یافت نشد.", False)
1176
+ return
1177
+
1178
+ is_file = False
1179
+ file_name = f"unknown_file_{uuid.uuid4().hex[:6]}.jpg"
1180
+
1181
+ if message.document:
1182
+ is_file = True
1183
+ file_name = message.document.file_name or file_name
1184
+ elif message.photo:
1185
+ is_file = True
1186
+ file_name = f"image_{uuid.uuid4().hex[:6]}.jpg"
1187
+ elif message.voice:
1188
+ is_file = True
1189
+ file_name = f"voice_{uuid.uuid4().hex[:6]}.ogg"
1190
+ elif message.audio:
1191
+ is_file = True
1192
+ file_name = message.audio.file_name or f"audio_{uuid.uuid4().hex[:6]}.mp3"
1193
+ elif message.video:
1194
+ is_file = True
1195
+ file_name = getattr(message.video, 'file_name', f"video_{uuid.uuid4().hex[:6]}.mp4")
1196
+
1197
+ str_chat_id = str(chat_id).replace("`", "").replace("'", "").replace('"', "").strip()
1198
+ creds = get_user_credits(str_chat_id)
1199
+
1200
+ if user_text_str == "✅ عضو شدم":
1201
+ if not creds.get("has_joined", False):
1202
+ user_credits_db[str_chat_id]["has_joined"] = True
1203
+ save_db(user_credits_db)
1204
+ await send_with_keyboard(bot, chat_id, "🎉 **عضویت شما با موفقیت تایید شد! خیلی خوش آمدید.**\n\nحالا می‌توانید از تمامی امکانات ربات استفاده کنید.\nلطفاً یکی از گزینه‌های منو را انتخاب کنید:", True)
1205
+ return
1206
+ else:
1207
+ await send_with_keyboard(bot, chat_id, "✅ شما قبلاً عضو شده‌اید! لطفا از منوی اصلی استفاده کنید.", True)
1208
+ return
1209
+
1210
+ if not creds.get("has_joined", False):
1211
+ join_msg = "👋 **سلام کاربر گرامی!**\n\nجهت استفاده از خدمات ربات هوش مصنوعی آلفا و مطلع شدن از آخرین آپدیت‌ها، لطفا ابتدا در کانال رسمی ما عضو شوید:\n\n📢 **آیدی کانال:** @aialpha\n\n👇 پس از عضویت در کانال، بر روی دک��ه **«✅ عضو شدم»** کلیک کنید تا ربات برای شما فعال شود."
1212
+ await bot.send_message(chat_id, join_msg, reply_markup=get_join_keyboard())
1213
+ return
1214
+
1215
+ if user_text_str in["/start", "سلام", "لغو", "/cancel", "❌ لغو", "برگشت♻️"]:
1216
+ user_states[chat_id]["mode"] = None
1217
+ user_states[chat_id]["file_bytes"] = None
1218
+ await send_with_keyboard(bot, chat_id, "سلام! به ربات هوش مصنوعی آلفا خوش آمدید 🤖\n\nلطفاً برای شروع، از کیبورد پایین یکی از بخش‌ها را انتخاب کنید:", True)
1219
+ return
1220
+
1221
+ # --- حساب کاربری ---
1222
+ if user_text_str in ["/account", "حساب کاربری 👤"]:
1223
+ creds = get_user_credits(chat_id)
1224
+ is_prem = creds.get("is_premium", False)
1225
+
1226
+ if is_prem:
1227
+ expire_txt = "نامشخص"
1228
+ days_left = 0
1229
+ if creds.get("expire_date"):
1230
+ exp_d = datetime.datetime.fromisoformat(creds["expire_date"])
1231
+ now = datetime.datetime.now()
1232
+ diff = exp_d - now
1233
+ days_left = diff.days if diff.days >= 0 else 0
1234
+
1235
+ jy, jm, jd = gregorian_to_jalali(exp_d.year, exp_d.month, exp_d.day)
1236
+ expire_txt = f"{jy:04d}/{jm:02d}/{jd:02d} (ساعت {exp_d.hour:02d}:{exp_d.minute:02d})"
1237
+
1238
+ status_text = "🌟 نسخه پرو (ویژه)"
1239
+ expire_info = f"\n📅 **تاریخ انقضا:** {expire_txt}\n⏳ **زمان باقیمانده:** {days_left} روز"
1240
+ daily_note = "*نکته: سهمیه پردازشی شما مختص همین دوره یک‌ماهه می‌باشد.*"
1241
+ else:
1242
+ status_text = "🥉 نسخه رایگان (آزمایشی)"
1243
+ expire_info = ""
1244
+ daily_note = "*نکته: سهمیه شما هر روز ساعت ۰۰:۰۰ بامداد به صورت خودکار مجدداً شارژ می‌گردد.*"
1245
+
1246
+ chat_rem = "نامحدود ∞" if is_prem else creds['chat']
1247
+ podcast_rem = "نامحدود ∞" if is_prem else creds['podcast']
1248
+ tts_rem = "نامحدود ∞" if is_prem else creds['tts']
1249
+ file_rem = "نامحدود ∞" if is_prem else creds['file']
1250
+ stt_rem = "نامحدود ∞" if is_prem else creds['stt']
1251
+ image_rem = creds['image']
1252
+ edit_image_rem = creds['edit_image']
1253
+
1254
+ account_profile = f"""👤 **اطلاعات حساب کاربری شما**
1255
+
1256
+ 🔹 **شناسه یکتا:** `{chat_id}`
1257
+ 🔹 **وضعیت اشتراک:** {status_text}{expire_info}
1258
+
1259
+ 📊 **سهمیه باقی‌مانده شما:**
1260
+ - 💬 چت هوشمند: {chat_rem}
1261
+ - 🎨 تولید تصویر: {image_rem} عدد
1262
+ - 🪄 ویرایش تصویر: {edit_image_rem} عدد
1263
+ - 🎙 ساخت پادکست: {podcast_rem}
1264
+ - 🗣 تبدیل متن به صدا: {tts_rem}
1265
+ - 📁 تحلیل فایل و سند: {file_rem}
1266
+ - 📝 تبدیل صدا به متن: {stt_rem}
1267
+
1268
+ {daily_note}"""
1269
+ await send_with_keyboard(bot, chat_id, account_profile, True)
1270
+ return
1271
+
1272
+ if user_text_str in["/buy", "خرید اشتراک 💎"]:
1273
+ buy_text = f"""💎 **خرید اشتراک ویژه آلفا پرو (یک ماهه)**
1274
+
1275
+ با تهیه اشتراک ویژه، محدودیت‌ها را کنار بزنید و از نهایت قدرت هوش مصنوعی لذت ببرید! 🚀
1276
+
1277
+ 🎁 **بسته طلایی یک‌ماهه شامل:**
1278
+ 🤖 چت با هوش مصنوعی بصورت نامحدود
1279
+ 🗣 تبدیل متن به صدا بصورت نامحدود با ۳۰ گوینده
1280
+ 🎙 ساخت پادکست بصورت نامحدود
1281
+
1282
+ 🪄 ۱۰ ویرایش تصویر
1283
+ 🎨 ۲۰ تولید تصویر
1284
+ 📁 تحلیل نامحدود فایل و سند
1285
+ 📝 تبدیل فایل صوتی به متن نامحدود
1286
+
1287
+ 💳 **هزینه اشتراک یک ماهه:** 250 هزار تومان
1288
+
1289
+ 💳 **شماره کارت جهت واریز:**
1290
+ `6219861411958035`
1291
+ 👤 **به نام:** کوهی
1292
+
1293
+ ✅ **نحوه فعال‌سازی:**
1294
+ پس از واریز مبلغ، لطفاً رسید پرداختی را به همراه **شناسه یکتای خود** (که در پایین آمده) به آیدی پشتیبانی زیر ارسال کنید تا اشتراک شما فعال گردد:
1295
+
1296
+ 🔑 **شناسه یکتای شما:** `{chat_id}`
1297
+
1298
+ 👨‍💻 **ارتباط با پشتیبانی:**
1299
+ 🆔 @H_a_m_e_d100"""
1300
+ await send_with_keyboard(bot, chat_id, buy_text, True)
1301
+ return
1302
+
1303
+ if user_text_str in["/transfer", "انتقال اکانت از برنامه به رب��ت"]:
1304
+ transfer_text = f"""🔄 **انتقال اکانت از برنامه به ربات**
1305
+
1306
+ کاربر گرامی، در صورتی که داخل برنامه «هوش مصنوعی آلفا» پیش‌تر اشتراک تهیه کرده‌اید، نیازی به خرید مجدد اشتراک داخل ربات نیست! 🎉
1307
+
1308
+ کافیست **شناسه یکتای** ربات خود را کپی کرده و برای پشتیبانی ما ارسال کنید تا اکانت اشتراکی شما به سرعت انتقال داده شود.
1309
+
1310
+ 🔑 **شناسه یکتای ربات شما:** `{chat_id}`
1311
+
1312
+ 👨‍💻 **پشتیبانی:**
1313
+ 🆔 @H_a_m_e_d100"""
1314
+ await send_with_keyboard(bot, chat_id, transfer_text, True)
1315
+ return
1316
+
1317
+ if user_text_str in["/chat", "💬 چت", "چت با هوش مصنوعی 🤖"]:
1318
+ user_states[chat_id]["mode"] = "chat"
1319
+ user_states[chat_id]["history"] =[]
1320
+ await send_with_keyboard(bot, chat_id, "💬 شما وارد بخش **چت با هوش مصنوعی** شدید.\n\nهر سوالی دارید بفرستید تا جواب بدم:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1321
+ return
1322
+
1323
+ if user_text_str in ["/image", "🎨 عکس", "ساخت تصاویر🎨"]:
1324
+ user_states[chat_id]["mode"] = "image_waiting_for_text"
1325
+ await send_with_keyboard(bot, chat_id, "🎨 شما وارد بخش **ساخت عکس پیشرفته** شدید.\n\nمتن خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1326
+ return
1327
+
1328
+ if user_text_str in["/edit_image", "ویرایش تصاویر 🪄"]:
1329
+ user_states[chat_id]["mode"] = "image_edit_waiting_for_image"
1330
+ user_states[chat_id]["file_bytes"] = None
1331
+ await send_with_keyboard(bot, chat_id, "🪄 به بخش **ویرایش عکس (Flux.2)** خوش آمدید.\n\nلطفاً ابتدا عکسی که می‌خواهید ویرایش کنید را بفرستید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1332
+ return
1333
+
1334
+ if user_text_str in["/tts", "🎙️ صدا", "تبدیل متن به صدا🗣️"]:
1335
+ user_states[chat_id]["mode"] = "tts_waiting_for_text"
1336
+ await send_with_keyboard(bot, chat_id, "🎙️ شما وارد بخش **تبدیل متن به صدا** شدید.\n\nلطفاً متنی که می‌خواهید به صدا تبدیل شود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1337
+ return
1338
+
1339
+ if user_text_str in["/podcast", "📻 پادکست", "ساخت پادکست 🎙️"]:
1340
+ user_states[chat_id]["mode"] = "podcast_waiting_for_topic"
1341
+ await send_with_keyboard(bot, chat_id, "📻 شما وارد بخش **ساخت پادکست** شدید.\n\nلطفاً موضوع پادکست خود را بفرستید.\nمثال: درباره تاریخچه پیدایش قهوه با ۳ گوینده یک پادکست جذاب بساز . همچنین این قسمت متصل به مدل زبانی است و درخواست هارو قبل از ساخت درک میکنه. میتوانید مقاله کامل یک سایت بفرستید با تبلیغات یا هرچی، هوش مصنوعی متن مقاله رو استخراج و پادکست براتون میسازه . در توضیحات امکان مشخص کردن تعداد گوینده به همراه اسم شون نیز از سمت شما امکان پذیر است.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1342
+ return
1343
+
1344
+ if user_text_str in ["/file", "تحلیل فایل 📁"]:
1345
+ user_states[chat_id]["mode"] = "file_waiting_for_file"
1346
+ user_states[chat_id]["file_bytes"] = None
1347
+ await send_with_keyboard(bot, chat_id, "📁 شما وارد بخش **تحلیل فایل اختصاصی** شدید.\n\nلطفاً فایل خود را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1348
+ return
1349
+
1350
+ if user_text_str in["/stt", "فایل صوتی به متن 📝"]:
1351
+ user_states[chat_id]["mode"] = "stt_waiting_for_audio"
1352
+ await send_with_keyboard(bot, chat_id, "📝 شما وارد بخش **تبدیل صدا به متن** شدید.\n\nلطفاً فایل خود (ویس، آهنگ، ویدیو و...) را ارسال کنید:\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1353
+ return
1354
+
1355
+ if user_text_str in["/create_file", "ساخت فایل 📄"]:
1356
+ user_states[chat_id]["mode"] = "create_file_waiting_for_topic"
1357
+ await send_with_keyboard(bot, chat_id, "📄 شما وارد بخش **ساخت فایل** شدید.\n\nلطفاً موضوع مقاله‌ای که می‌خواهید را کامل بفرستید.\nمثال: نحوه مدیریت زمان\n\nهوش مصنوعی یک مقاله کامل و طولانی نوشته و در نهایت فایل PDF و Word آن را به شما تحویل می‌دهد.\n\n(برای خروج دکمه «برگشت♻️» را بزنید)", True)
1358
+ return
1359
+
1360
+ current_mode = user_states[chat_id].get("mode")
1361
+
1362
+ if current_mode is None:
1363
+ if is_file: pass
1364
+ elif user_text_str: await send_with_keyboard(bot, chat_id, "⚠️ لطفاً ابتدا از کیبورد پایین، بخش مورد نظرتان را انتخاب کنید:", True)
1365
+ return
1366
+
1367
+ elif current_mode == "chat":
1368
+ if is_file:
1369
+ await send_with_keyboard(bot, chat_id, "📥 در حال دانلود فایل...", False)
1370
+ try:
1371
+ file_bytes = await helper_download_file(bot, message)
1372
+ asyncio.create_task(process_gemini(bot, chat_id, user_text_str, file_bytes=file_bytes, file_name=file_name))
1373
+ except Exception as dl_err: await send_with_keyboard(bot, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
1374
+ elif user_text_str: asyncio.create_task(process_gemini(bot, chat_id, user_text_str))
1375
+ return
1376
+
1377
+ elif current_mode == "image_waiting_for_text":
1378
+ if user_text_str: asyncio.create_task(process_image(bot, chat_id, user_text_str))
1379
+ return
1380
+
1381
+ elif current_mode == "image_edit_waiting_for_image":
1382
+ if not is_file: return await send_with_keyboard(bot, chat_id, "⚠️ لطفاً ابتدا یک عکس ارسال کنید.", False)
1383
+ await send_with_keyboard(bot, chat_id, "📥 در حال دانلود عکس...", False)
1384
+ try:
1385
+ file_bytes = await helper_download_file(bot, message)
1386
+ user_states[chat_id]["file_bytes"] = file_bytes
1387
+ user_states[chat_id]["mode"] = "image_edit_waiting_for_prompt"
1388
+ await send_with_keyboard(bot, chat_id, "✅ عکس با موفقیت دریافت شد.\n\nحالا دستور خود را به صورت متنی تایپ کنید.\nمثال: یک کلاه قرمز روی سر این گربه بگذار.", False)
1389
+ except Exception as dl_err: await send_with_keyboard(bot, chat_id, f"❌ خطا در دریافت عکس!\n{str(dl_err)}", False)
1390
+ return
1391
+
1392
+ elif current_mode == "image_edit_waiting_for_prompt":
1393
+ if user_text_str:
1394
+ saved_bytes = user_states[chat_id].get("file_bytes")
1395
+ user_states[chat_id]["mode"] = None
1396
+ user_states[chat_id]["file_bytes"] = None
1397
+ asyncio.create_task(process_image_edit(bot, chat_id, saved_bytes, user_text_str))
1398
+ else: await send_with_keyboard(bot, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1399
+ return
1400
+
1401
+ elif current_mode == "tts_waiting_for_text":
1402
+ if user_text_str:
1403
+ if len(user_text_str) > 2500: return await send_with_keyboard(bot, chat_id, "⚠️ لطفاً متنی کوتاه‌تر از 2500 کاراکتر بفرستید.", False)
1404
+ user_states[chat_id]["text"] = user_text_str
1405
+ user_states[chat_id]["mode"] = "tts_waiting_for_speaker"
1406
+
1407
+ speakers_menu = """✅ متن شما ذخیره شد.
1408
+ لطفاً **شماره** گوینده مورد نظر خود را بفرستید:
1409
+ 1. شهاب | 2. آوا | 3. نوید
1410
+ 4. آرمان | 5. مهسا | 6. دانا
1411
+ 7. سامان | 8. آرش | 9. شبنم
1412
+ 10. سحر | 11. مریم | 12. بهرام
1413
+ 13. نیکان| 14. فرناز | 15. سارا
1414
+ 16. مانی | 17. آرتین | 18. دلنواز
1415
+ 19. روژان | 20. امید | 21. بردیا
1416
+ 22. ترانه | 23. نیکو | 24. هستی
1417
+ 25. کامیار| 26. کیانوش| 27. پویا
1418
+ 28. مهتاب | 29. سام | 30. لیدا"""
1419
+ await send_with_keyboard(bot, chat_id, speakers_menu, False)
1420
+ return
1421
+
1422
+ elif current_mode == "tts_waiting_for_speaker":
1423
+ normalized_text = to_english_digits(user_text_str)
1424
+
1425
+ if normalized_text.isdigit() and normalized_text in SPEAKERS:
1426
+ spk_name, spk_id = SPEAKERS[normalized_text]
1427
+ txt = user_states[chat_id]["text"]
1428
+ user_states[chat_id]["mode"] = "tts_waiting_for_text"
1429
+ asyncio.create_task(process_tts(bot, chat_id, txt, spk_id, spk_name))
1430
+ else:
1431
+ await send_with_keyboard(bot, chat_id, "❌ شماره نامعتبر است! لطفاً فقط یک عدد بین 1 تا 30 بفرستید.", False)
1432
+ return
1433
+
1434
+ elif current_mode == "podcast_waiting_for_topic":
1435
+ if user_text_str: asyncio.create_task(process_podcast(bot, chat_id, user_text_str))
1436
+ else: await send_with_keyboard(bot, chat_id, "⚠️ لطفاً موضوع پادکست خود را به صورت متنی بفرستید.", False)
1437
+ return
1438
+
1439
+ elif current_mode == "stt_waiting_for_audio":
1440
+ if not is_file: return await send_with_keyboard(bot, chat_id, "⚠️ لطفاً یک فایل ارسال کنید.", False)
1441
+ await send_with_keyboard(bot, chat_id, "📥 در حال دانلود فایل...", False)
1442
+ try:
1443
+ audio_bytes = await helper_download_file(bot, message)
1444
+ asyncio.create_task(process_stt(bot, chat_id, audio_bytes, file_name))
1445
+ except Exception as dl_err: await send_with_keyboard(bot, chat_id, f"❌ خطا در دانلود فایل!\n{str(dl_err)}", False)
1446
+ return
1447
+
1448
+ elif current_mode == "file_waiting_for_file":
1449
+ if not is_file: return await send_with_keyboard(bot, chat_id, "⚠️ لطفاً ابتدا یک فایل ارسال کنید.", False)
1450
+ await send_with_keyboard(bot, chat_id, "📥 در حال دریافت فایل...", False)
1451
+ try:
1452
+ file_bytes = await helper_download_file(bot, message)
1453
+ user_states[chat_id]["file_bytes"] = file_bytes
1454
+ user_states[chat_id]["file_name"] = file_name
1455
+ user_states[chat_id]["mode"] = "file_waiting_for_prompt"
1456
+ await send_with_keyboard(bot, chat_id, "✅ فایل با موفقیت دریافت شد.\n\nحالا لطفاً متنی بگویید **چگونه تحلیل شود؟**", False)
1457
+ except Exception as dl_err: await send_with_keyboard(bot, chat_id, f"❌ خطا در دریافت فایل!\n{str(dl_err)}", False)
1458
+ return
1459
+
1460
+ elif current_mode == "file_waiting_for_prompt":
1461
+ if user_text_str:
1462
+ saved_bytes = user_states[chat_id].get("file_bytes")
1463
+ saved_name = user_states[chat_id].get("file_name", "file.jpeg")
1464
+ user_states[chat_id]["mode"] = "file_waiting_for_file"
1465
+ asyncio.create_task(process_file_analysis(bot, chat_id, saved_bytes, saved_name, user_text_str))
1466
+ else: await send_with_keyboard(bot, chat_id, "⚠️ لطفاً درخواست خود را متنی بنویسید.", False)
1467
+ return
1468
+
1469
+ elif current_mode == "create_file_waiting_for_topic":
1470
+ if user_text_str:
1471
+ asyncio.create_task(process_create_file(bot, chat_id, user_text_str))
1472
+ else:
1473
+ await send_with_keyboard(bot, chat_id, "⚠️ لطفاً موضوع مقاله خود را به صورت متنی بفرستید.", False)
1474
+ return
1475
+
1476
+ except Exception: traceback.print_exc()
1477
+
1478
+ if __name__ == "__main__":
1479
+ threading.Thread(target=run_flask, daemon=True).start()
1480
+ if not bot_token:
1481
+ print("خطا: توکن ربات بله وارد نشده است! لطفا متغیر BALE_TOKEN را تنظیم کنید.")
1482
+ else:
1483
+ print("ربات آلفا پرو با سیستم اشتراک نامحدود + سپر امنیتی متصل به پیامرسان «بله» روشن شد... 🚀")
1484
+ asyncio.run(bot.polling(non_stop=True, request_timeout=90))