Kaveh commited on
Commit
38ddf80
·
unverified ·
1 Parent(s): 60cf662

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -57
app.py CHANGED
@@ -8,6 +8,7 @@ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
8
  import re
9
  import nltk
10
  from nltk.tokenize import sent_tokenize
 
11
 
12
  # تنظیم cache directory
13
  cache_dir = '/tmp/transformers_cache'
@@ -30,8 +31,8 @@ logger = logging.getLogger(__name__)
30
  message_storage = {}
31
  MAX_MESSAGES_PER_CHAT = 1000
32
 
33
- # مدل سبک‌تر برای CPU رایگان
34
- MODEL_NAME = "sshleifer/distilbart-cnn-6-6" # خیلی سبک‌تر از bart-large
35
  model = None
36
  tokenizer = None
37
 
@@ -75,10 +76,10 @@ class MessageStore:
75
  # ایجاد نمونه از مخزن پیام‌ها
76
  message_store = MessageStore()
77
 
78
- def load_lightweight_model():
79
- """بارگیری مدل سبک"""
80
  try:
81
- logger.info(f"Loading lightweight model: {MODEL_NAME}")
82
 
83
  tokenizer = AutoTokenizer.from_pretrained(
84
  MODEL_NAME,
@@ -89,30 +90,22 @@ def load_lightweight_model():
89
  model = AutoModelForSeq2SeqLM.from_pretrained(
90
  MODEL_NAME,
91
  cache_dir=cache_dir,
92
- local_files_only=False
 
 
93
  )
94
 
95
- logger.info("Model loaded successfully")
 
96
  return model, tokenizer
97
 
98
  except Exception as e:
99
- logger.error(f"Error loading model: {e}")
100
- # مدل فوق سبک جایگزین
101
- try:
102
- logger.info("Trying ultra-light model...")
103
- alt_model = "sshleifer/distilbart-cnn-2-2"
104
-
105
- tokenizer = AutoTokenizer.from_pretrained(alt_model, cache_dir=cache_dir)
106
- model = AutoModelForSeq2SeqLM.from_pretrained(alt_model, cache_dir=cache_dir)
107
-
108
- return model, tokenizer
109
- except Exception as e2:
110
- logger.error(f"Failed to load any model: {e2}")
111
- return None, None
112
 
113
  def preprocess_persian_text(text):
114
- """پیش‌پردازش متن فارسی"""
115
- # حذف کاراکترهای اضافی
116
  text = re.sub(r'\s+', ' ', text) # چندین فاصله -> یک فاصله
117
  text = re.sub(r'\n+', '\n', text) # چندین خط جدید -> یک خط
118
 
@@ -120,14 +113,21 @@ def preprocess_persian_text(text):
120
  text = re.sub(r'\d{2}:\d{2}', '', text) # زمان
121
  text = re.sub(r'@\w+', '', text) # منشن‌ها
122
 
 
 
 
 
 
 
123
  return text.strip()
124
 
125
- def chunk_text_smart(text, max_length=400):
126
- """تقسیم هوشمند متن"""
127
  try:
128
  sentences = sent_tokenize(text)
129
  except:
130
- sentences = re.split(r'[.!?]+', text)
 
131
 
132
  chunks = []
133
  current_chunk = ""
@@ -150,7 +150,7 @@ def chunk_text_smart(text, max_length=400):
150
  return chunks
151
 
152
  def summarize_messages(messages_data):
153
- """خلاصه‌سازی پیام‌های گروه"""
154
  global model, tokenizer
155
 
156
  if not model or not tokenizer:
@@ -173,30 +173,34 @@ def summarize_messages(messages_data):
173
  return "❌ متن برای خلاصه‌سازی بسیار کوتاه است"
174
 
175
  # تقسیم به بخش‌های کوچک
176
- chunks = chunk_text_smart(combined_text, max_length=350)
177
  summaries = []
178
 
179
- for i, chunk in enumerate(chunks[:3]): # حداکثر 3 بخش برای جلوگیری از timeout
180
  try:
181
  inputs = tokenizer.encode(
182
- chunk,
183
  return_tensors="pt",
184
- max_length=400,
185
  truncation=True
186
  )
187
 
188
- # تنظیمات سبک‌تر برای CPU
189
  summary_ids = model.generate(
190
  inputs,
191
- max_length=80, # کوتاه‌تر
192
- min_length=20,
193
- length_penalty=1.5, # کمتر
194
- num_beams=2, # کمتر
195
  early_stopping=True,
196
- no_repeat_ngram_size=2
197
  )
198
 
199
  summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
 
 
 
 
 
200
  summaries.append(summary)
201
 
202
  except Exception as e:
@@ -259,33 +263,39 @@ def parse_summary_request(text):
259
 
260
  async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
261
  """شروع ربات"""
262
- welcome_msg = """
263
  🤖 سلام! من ربات خلاصه‌ساز گروه هستم.
264
 
265
  📋 برای استفاده از من:
266
- - من را با @{} تگ کنید
267
  - بعد عبارت "خلاصه" یا "خلاصه کن" بنویسید
268
 
269
  🔹 مثال‌ها:
270
- • @{} خلاصه کن
271
- • @{} خلاصه 100 پیام آخر
272
- • @{} خلاصه 2 ساعت اخیر
273
- • @{} خلاصه کن آخرین 50 پیام
274
 
275
  ⚙️ دستورات:
276
  /help - راهنمای کامل
277
  /stats - آمار گروه
 
278
 
279
  🔸 توجه: من فقط وقتی تگ شوم کار می‌کنم!
280
- """.format(
281
- context.bot.username,
282
- context.bot.username,
283
- context.bot.username,
284
- context.bot.username
285
- )
286
 
287
  await update.message.reply_text(welcome_msg)
288
 
 
 
 
 
 
 
 
 
 
 
 
289
  async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
290
  """راهنمای کامل"""
291
  help_text = f"""
@@ -300,15 +310,20 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
300
  • @{context.bot.username} خلاصه کن
301
  • @{context.bot.username} خلاصه 50 پیام
302
  • @{context.bot.username} خلاصه 3 ساعت اخیر
303
- • @{context.bot.username} خلاصه کن آخرین 100 تا
304
 
305
  ⚡ ویژگی‌ها:
306
  • پردازش تا 200 پیام
307
  • بازه زمانی تا 3 روز
308
- حفظ نام کاربران در خلاصه
309
- آمارگیری از گفتگو
 
 
 
 
 
 
310
 
311
- 🔸 نکته: من فقط در گروه‌ها کار می‌کنم و فقط وقتی تگ شوم!
312
  """
313
  await update.message.reply_text(help_text)
314
 
@@ -420,12 +435,12 @@ def main():
420
  logger.error("BOT_TOKEN not found!")
421
  return
422
 
423
- # بارگیری مدل
424
- logger.info("Loading model...")
425
- model, tokenizer = load_lightweight_model()
426
 
427
  if not model:
428
- logger.error("Failed to load model!")
429
  return
430
 
431
  # ساخت اپلیکیشن
@@ -435,6 +450,7 @@ def main():
435
  app.add_handler(CommandHandler("start", start))
436
  app.add_handler(CommandHandler("help", help_command))
437
  app.add_handler(CommandHandler("stats", stats_command))
 
438
 
439
  # Handler برای تمام پیام‌ها (ذخیره + پردازش)
440
  app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
@@ -443,7 +459,7 @@ def main():
443
  app.add_error_handler(error_handler)
444
 
445
  # شروع
446
- logger.info("Bot started! Waiting for messages...")
447
  app.run_polling(drop_pending_updates=True)
448
 
449
  if __name__ == '__main__':
 
8
  import re
9
  import nltk
10
  from nltk.tokenize import sent_tokenize
11
+ import torch
12
 
13
  # تنظیم cache directory
14
  cache_dir = '/tmp/transformers_cache'
 
31
  message_storage = {}
32
  MAX_MESSAGES_PER_CHAT = 1000
33
 
34
+ # مدل فارسی
35
+ MODEL_NAME = "nafisehNik/mt5-persian-summary"
36
  model = None
37
  tokenizer = None
38
 
 
76
  # ایجاد نمونه از مخزن پیام‌ها
77
  message_store = MessageStore()
78
 
79
+ def load_persian_model():
80
+ """بارگیری مدل فارسی"""
81
  try:
82
+ logger.info(f"Loading Persian model: {MODEL_NAME}")
83
 
84
  tokenizer = AutoTokenizer.from_pretrained(
85
  MODEL_NAME,
 
90
  model = AutoModelForSeq2SeqLM.from_pretrained(
91
  MODEL_NAME,
92
  cache_dir=cache_dir,
93
+ local_files_only=False,
94
+ torch_dtype=torch.float32,
95
+ low_cpu_mem_usage=True,
96
  )
97
 
98
+ model.eval()
99
+ logger.info("Persian model loaded successfully")
100
  return model, tokenizer
101
 
102
  except Exception as e:
103
+ logger.error(f"Error loading Persian model: {e}")
104
+ return None, None
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  def preprocess_persian_text(text):
107
+ """پیش‌پردازش پیشرفته متن فارسی"""
108
+ # حذف کاراکترهای اضافی و تمیز کردن
109
  text = re.sub(r'\s+', ' ', text) # چندین فاصله -> یک فاصله
110
  text = re.sub(r'\n+', '\n', text) # چندین خط جدید -> یک خط
111
 
 
113
  text = re.sub(r'\d{2}:\d{2}', '', text) # زمان
114
  text = re.sub(r'@\w+', '', text) # منشن‌ها
115
 
116
+ # حذف لینک‌ها
117
+ text = re.sub(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', '', text)
118
+
119
+ # حذف ایموجی‌ها
120
+ text = re.sub(r'[^\w\s\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]', ' ', text)
121
+
122
  return text.strip()
123
 
124
+ def chunk_text_smart(text, max_length=300):
125
+ """تقسیم هوشمند متن با در نظر گیری زبان فارسی"""
126
  try:
127
  sentences = sent_tokenize(text)
128
  except:
129
+ # روش جایگزین برای جمله‌بندی فارسی
130
+ sentences = re.split(r'[.!?؟۔]+', text)
131
 
132
  chunks = []
133
  current_chunk = ""
 
150
  return chunks
151
 
152
  def summarize_messages(messages_data):
153
+ """خلاصه‌سازی پیام‌های گروه با مدل فارسی"""
154
  global model, tokenizer
155
 
156
  if not model or not tokenizer:
 
173
  return "❌ متن برای خلاصه‌سازی بسیار کوتاه است"
174
 
175
  # تقسیم به بخش‌های کوچک
176
+ chunks = chunk_text_smart(combined_text, max_length=400)
177
  summaries = []
178
 
179
+ for i, chunk in enumerate(chunks[:2]): # حداکثر 2 بخش
180
  try:
181
  inputs = tokenizer.encode(
182
+ f"خلاصه: {chunk}",
183
  return_tensors="pt",
184
+ max_length=512,
185
  truncation=True
186
  )
187
 
 
188
  summary_ids = model.generate(
189
  inputs,
190
+ max_length=100,
191
+ min_length=30,
192
+ length_penalty=1.2,
193
+ num_beams=3,
194
  early_stopping=True,
195
+ no_repeat_ngram_size=3
196
  )
197
 
198
  summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
199
+
200
+ # پاک کردن prefix
201
+ if summary.startswith("خلاصه:"):
202
+ summary = summary[5:].strip()
203
+
204
  summaries.append(summary)
205
 
206
  except Exception as e:
 
263
 
264
  async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
265
  """شروع ربات"""
266
+ welcome_msg = f"""
267
  🤖 سلام! من ربات خلاصه‌ساز گروه هستم.
268
 
269
  📋 برای استفاده از من:
270
+ - من را با @{context.bot.username} تگ کنید
271
  - بعد عبارت "خلاصه" یا "خلاصه کن" بنویسید
272
 
273
  🔹 مثال‌ها:
274
+ • @{context.bot.username} خلاصه کن
275
+ • @{context.bot.username} خلاصه 100 پیام آخر
276
+ • @{context.bot.username} خلاصه 2 ساعت اخیر
 
277
 
278
  ⚙️ دستورات:
279
  /help - راهنمای کامل
280
  /stats - آمار گروه
281
+ /model - اطلاعات مدل فعلی
282
 
283
  🔸 توجه: من فقط وقتی تگ شوم کار می‌کنم!
284
+ """
 
 
 
 
 
285
 
286
  await update.message.reply_text(welcome_msg)
287
 
288
+ async def model_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
289
+ """نمایش اطلاعات مدل فعلی"""
290
+ info_text = f"""
291
+ 🤖 اطلاعات مدل فعلی:
292
+
293
+ 📦 نام مدل: {MODEL_NAME}
294
+ 🌐 پشتیبانی زبان: ✅ فارسی
295
+ 💾 وضعیت: فعال و آماده
296
+ """
297
+ await update.message.reply_text(info_text)
298
+
299
  async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
300
  """راهنمای کامل"""
301
  help_text = f"""
 
310
  • @{context.bot.username} خلاصه کن
311
  • @{context.bot.username} خلاصه 50 پیام
312
  • @{context.bot.username} خلاصه 3 ساعت اخیر
 
313
 
314
  ⚡ ویژگی‌ها:
315
  • پردازش تا 200 پیام
316
  • بازه زمانی تا 3 روز
317
+ پشتیبانی از متن فارسی
318
+ تطبیق خودکار با بهترین مدل موجود
319
+
320
+ 🔧 دستورات:
321
+ /start - شروع
322
+ /help - راهنما
323
+ /stats - آمار گروه
324
+ /model - اطلاعات مدل
325
 
326
+ 🔸 نکته: من فقط در گروه‌ها و وقتی تگ شوم کار می‌کنم!
327
  """
328
  await update.message.reply_text(help_text)
329
 
 
435
  logger.error("BOT_TOKEN not found!")
436
  return
437
 
438
+ # بارگیری مدل فارسی
439
+ logger.info("Loading Persian model...")
440
+ model, tokenizer = load_persian_model()
441
 
442
  if not model:
443
+ logger.error("Failed to load any model!")
444
  return
445
 
446
  # ساخت اپلیکیشن
 
450
  app.add_handler(CommandHandler("start", start))
451
  app.add_handler(CommandHandler("help", help_command))
452
  app.add_handler(CommandHandler("stats", stats_command))
453
+ app.add_handler(CommandHandler("model", model_info))
454
 
455
  # Handler برای تمام پیام‌ها (ذخیره + پردازش)
456
  app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
 
459
  app.add_error_handler(error_handler)
460
 
461
  # شروع
462
+ logger.info(f"Bot started with Persian model: {MODEL_NAME}")
463
  app.run_polling(drop_pending_updates=True)
464
 
465
  if __name__ == '__main__':