Mustafa-albakkar commited on
Commit
d993f05
·
verified ·
1 Parent(s): 4be75eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -60
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # ============================================================
2
- # analyzer_agent_gradio/app.py — Telegram Analyzer Agent (Webhook & Gradio)
3
  # Mamba + GGUF LLM + python-telegram-bot + Gradio
4
  # ============================================================
5
 
@@ -22,9 +22,10 @@ from transformers import AutoTokenizer, AutoModelForCausalLM
22
  import telegram
23
  from telegram.error import TelegramError, BadRequest
24
  # استيرادات Webhook/Handlers
25
- from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext # <<< إضافة هامة للـ Handlers
26
  from llama_cpp import Llama
27
  from huggingface_hub import hf_hub_download
 
28
 
29
 
30
  # ---------------- Logging ----------------
@@ -35,26 +36,27 @@ log = logging.getLogger("analyzer")
35
  # ---------------- Env & config ----------------
36
  TG_BOT_TOKEN = os.getenv("TG_BOT_TOKEN")
37
  TG_CHANNEL = os.getenv("TG_CHANNEL")
 
 
38
  LOG_PATH = os.getenv("ANALYZER_LOG", "analyzer_log.json")
39
  POSTS_LIMIT = int(os.getenv("ANALYZER_LIMIT", "80"))
40
 
41
  MAMBA_MODEL_PATH = os.getenv("MAMBA_MODEL_PATH", "state-spaces/mamba-1.4b-hf")
42
 
43
  # ---------------- Webhook Config ----------------
44
- # يجب تحديد هذا المتغير في بيئة التشغيل للعمل بوضع Webhook
45
- # مثال: https://your-domain.com/telegram_webhook_path
46
  WEBHOOK_URL = os.getenv("WEBHOOK_URL")
47
- WEBHOOK_PORT = int(os.getenv("WEBHOOK_PORT", "8443")) # المنفذ الذي سيستمع عليه الخادم
48
  LISTEN_ADDRESS = os.getenv("LISTEN_ADDRESS", "0.0.0.0")
49
 
50
  # ---------------- Initialization Check ----------------
51
- if not all([TG_BOT_TOKEN, TG_CHANNEL]):
52
- log.error("Telegram Bot Token or Channel ID are missing in environment variables.")
53
  IS_SERVICE_READY = False
54
- STATUS_MESSAGE = "❌ النظام غير جاهز: بيانات اعتماد البوت أو معرف القناة مفقودة."
55
  else:
56
  IS_SERVICE_READY = True
57
- STATUS_MESSAGE = "✅ النظام جاهز للتحليل (Bot API)."
 
58
 
59
  # ---------------- Helpers for Non-Async Blocking Operations ----------------
60
  def async_wrap_blocking(func):
@@ -100,7 +102,7 @@ try:
100
  model_path=LLM_LOCAL_PATH,
101
  n_ctx=4096,
102
  n_threads=4,
103
- n_gpu_layers=0 # إذا لديك GPU ضع قيمة أكبر
104
  )
105
  log.info("GGUF model loaded successfully.")
106
  except Exception as e:
@@ -109,18 +111,17 @@ except Exception as e:
109
  STATUS_MESSAGE = "❌ فشل تحميل نموذج GGUF."
110
 
111
 
112
- # ---------------- Telegram Bot Client ----------------
113
- # تعريف البوت
114
  if IS_SERVICE_READY:
115
  try:
116
- # إنشاء كائن البوت (هذا أصبح يتم عبر Application الآن)
117
- bot_client = telegram.Bot(token=TG_BOT_TOKEN)
118
  except Exception as e:
119
  log.error(f"Failed to initialize Telegram Bot: {e}")
120
  IS_SERVICE_READY = False
121
  STATUS_MESSAGE = "❌ فشل تهيئة كائن البوت."
122
- else:
123
- bot_client = None
124
 
125
  # ---------------- Core Helpers ----------------
126
  def save_log(entry: Dict[str, Any]):
@@ -190,50 +191,83 @@ def interpret_with_llm(mamba_output: str) -> str:
190
  return res["choices"][0]["text"].strip()
191
 
192
 
193
- # ---------------- Fetch Telegram Stats (Bot API) ----------------
194
  async def fetch_telegram_stats(limit: int = POSTS_LIMIT) -> List[Dict[str, Any]]:
195
- """Fetches general channel statistics from Telegram asynchronously using Bot API."""
196
- # نستخدم bot_client لضمان وجود الكائن، أو Context.bot في الـ Handlers
197
- if not IS_SERVICE_READY or bot_client is None:
 
 
198
  raise RuntimeError(STATUS_MESSAGE)
199
 
200
- try:
201
- log.info("Attempting to fetch channel info and administrators...")
202
-
203
- # 1. جلب معلومات القناة الأساسية
204
- chat_info = await bot_client.get_chat(chat_id=TG_CHANNEL)
205
 
206
- # 2. جلب المشرفين
207
- admins = await bot_client.get_chat_administrators(chat_id=TG_CHANNEL)
208
- admins_count = len(admins)
209
-
210
- # تحويل البيانات إلى تنسيق موحد للتحليل
211
- stats = {
212
- "chat_id": chat_info.id,
213
- "title": chat_info.title,
214
- "members": chat_info.members_count,
215
- "admins_count": admins_count,
216
- "description": chat_info.description,
217
- "date": datetime.utcnow().isoformat(),
218
- }
 
 
 
 
 
 
219
 
220
- log.info(f"Successfully fetched stats for channel {stats['title']} with {stats['members']} members.")
221
- return [stats]
222
-
223
- except BadRequest as e:
224
- error_msg = str(e).lower()
225
- if 'unauthorized' in error_msg or 'forbidden' in error_msg:
226
- log.error("Telegram Auth Error: The Bot Token is invalid or Bot is not a member.")
227
- raise RuntimeError("فشل مصادقة Telegram: تأكد من صحة TG_BOT_TOKEN وأن البوت عضو في القناة.")
228
- else:
229
- log.error(f"Telegram Bot API Error: {e}")
230
- raise RuntimeError(f"قناة Telegram غير صالحة: {TG_CHANNEL}. التفاصيل: {e}.")
231
- except TelegramError as e:
232
- log.error(f"An unexpected Telegram error occurred: {e}")
233
- raise RuntimeError(f"خطأ غير متوقع في Telegram: {e}")
234
- except Exception as e:
235
- log.error(f"An unexpected error occurred during Telegram fetch: {e}")
236
- raise RuntimeError(f"خطأ غير متوقع في جلب البيانات: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
 
239
  # ---------------- Main Analysis Pipeline ----------------
@@ -362,7 +396,6 @@ def daily_job_wrapper():
362
  """Synchronous wrapper to run the async job in the scheduler."""
363
  log.info("Running scheduled analysis job via Gradio wrapper...")
364
  try:
365
- # تشغيل الدالة async في حلقة الحدث الخاصة بها
366
  result = asyncio.run(run_analysis_pipeline())
367
  log.info(f"Scheduled job completed. Status: {result.get('status')}")
368
  except Exception as e:
@@ -376,6 +409,7 @@ with gr.Blocks(title="Telegram Channel Analyzer Agent") as demo:
376
  gr.Markdown("# 🤖 وكيل تحليل قناة Telegram (Webhook/Scheduled)")
377
  gr.Markdown(f"**حالة الخدمة:** {STATUS_MESSAGE}")
378
  gr.Markdown(f"**القناة المستهدفة:** `{TG_CHANNEL}`")
 
379
  gr.Markdown("---")
380
 
381
  with gr.Tab("تشغيل التحليل يدوياً"):
@@ -448,19 +482,15 @@ if __name__ == "__main__":
448
  # وضع Webhook
449
  log.info(f"Setting Webhook URL to: {WEBHOOK_URL}")
450
  try:
451
- # يجب تعيين الـ URL بالكامل لـ Telegram
452
  application.bot.set_webhook(url=WEBHOOK_URL)
453
 
454
  log.info(f"Starting Webhook server on {LISTEN_ADDRESS}:{WEBHOOK_PORT}...")
455
- # المسار الذي سيستمع عليه الخادم (يجب أن يتطابق مع الجزء الأخير من WEBHOOK_URL)
456
  url_path = WEBHOOK_URL.split('/')[-1] if WEBHOOK_URL.count('/') > 2 else ""
457
 
458
- # تشغيل خادم Webhook
459
  application.run_webhook(
460
  listen=LISTEN_ADDRESS,
461
  port=WEBHOOK_PORT,
462
  url_path=url_path,
463
- # Note: يجب استخدام HTTPS وشهادة SSL/TLS في بيئة الإنتاج
464
  )
465
  except Exception as e:
466
  log.error(f"Failed to start Webhook: {e}")
 
1
  # ============================================================
2
+ # analyzer_agent_gradio/app.py — Telegram Analyzer Agent (Via Replit Proxy)
3
  # Mamba + GGUF LLM + python-telegram-bot + Gradio
4
  # ============================================================
5
 
 
22
  import telegram
23
  from telegram.error import TelegramError, BadRequest
24
  # استيرادات Webhook/Handlers
25
+ from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext
26
  from llama_cpp import Llama
27
  from huggingface_hub import hf_hub_download
28
+ import requests # <<< إضافة هامة للاتصال بالجسر
29
 
30
 
31
  # ---------------- Logging ----------------
 
36
  # ---------------- Env & config ----------------
37
  TG_BOT_TOKEN = os.getenv("TG_BOT_TOKEN")
38
  TG_CHANNEL = os.getenv("TG_CHANNEL")
39
+ # المتغير الجديد: رابط تطبيق الجسر على Replit
40
+ REPLIT_PROXY_URL = os.getenv("REPLIT_PROXY_URL")
41
  LOG_PATH = os.getenv("ANALYZER_LOG", "analyzer_log.json")
42
  POSTS_LIMIT = int(os.getenv("ANALYZER_LIMIT", "80"))
43
 
44
  MAMBA_MODEL_PATH = os.getenv("MAMBA_MODEL_PATH", "state-spaces/mamba-1.4b-hf")
45
 
46
  # ---------------- Webhook Config ----------------
 
 
47
  WEBHOOK_URL = os.getenv("WEBHOOK_URL")
48
+ WEBHOOK_PORT = int(os.getenv("WEBHOOK_PORT", "8443"))
49
  LISTEN_ADDRESS = os.getenv("LISTEN_ADDRESS", "0.0.0.0")
50
 
51
  # ---------------- Initialization Check ----------------
52
+ if not all([TG_BOT_TOKEN, TG_CHANNEL, REPLIT_PROXY_URL]): # <<< تعديل التحقق
53
+ log.error("Telegram Bot Token, Channel ID, or Replit Proxy URL are missing in environment variables.")
54
  IS_SERVICE_READY = False
55
+ STATUS_MESSAGE = "❌ النظام غير جاهز: بيانات اعتماد البوت، معرف القناة، أو رابط الجسر مفقودة."
56
  else:
57
  IS_SERVICE_READY = True
58
+ STATUS_MESSAGE = "✅ النظام جاهز للتحليل (Bot API via Replit Proxy)."
59
+
60
 
61
  # ---------------- Helpers for Non-Async Blocking Operations ----------------
62
  def async_wrap_blocking(func):
 
102
  model_path=LLM_LOCAL_PATH,
103
  n_ctx=4096,
104
  n_threads=4,
105
+ n_gpu_layers=0
106
  )
107
  log.info("GGUF model loaded successfully.")
108
  except Exception as e:
 
111
  STATUS_MESSAGE = "❌ فشل تحميل نموذج GGUF."
112
 
113
 
114
+ # ---------------- Telegram Bot Client (for Webhook handlers) ----------------
115
+ # لا يزال هذا الكائن ضرورياً لـ python-telegram-bot لاستقبال الأوامر والرد
116
  if IS_SERVICE_READY:
117
  try:
118
+ # لا نحتاج لـ bot_client لكن نحتاج للتحقق من التوكن لـ Application.builder
119
+ pass
120
  except Exception as e:
121
  log.error(f"Failed to initialize Telegram Bot: {e}")
122
  IS_SERVICE_READY = False
123
  STATUS_MESSAGE = "❌ فشل تهيئة كائن البوت."
124
+
 
125
 
126
  # ---------------- Core Helpers ----------------
127
  def save_log(entry: Dict[str, Any]):
 
191
  return res["choices"][0]["text"].strip()
192
 
193
 
194
+ # ---------------- FETCH TELEGRAM STATS (VIA REPLIT PROXY) ----------------
195
  async def fetch_telegram_stats(limit: int = POSTS_LIMIT) -> List[Dict[str, Any]]:
196
+ """
197
+ Fetches general channel statistics by routing requests through the Replit Proxy.
198
+ """
199
+
200
+ if not IS_SERVICE_READY or not REPLIT_PROXY_URL:
201
  raise RuntimeError(STATUS_MESSAGE)
202
 
203
+ async def fetch_via_proxy(method: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
204
+ """Sends a request to the Replit proxy and returns the Telegram response result."""
205
+ url = f"{REPLIT_PROXY_URL}/route_telegram/{method}"
 
 
206
 
207
+ try:
208
+ # نستخدم to_thread لجعل طلب requests متزامن (Blocking) يعمل في خيط منفصل
209
+ response = await asyncio.to_thread(
210
+ requests.post,
211
+ url,
212
+ json=data if data is not None else {},
213
+ timeout=30
214
+ )
215
+ response.raise_for_status()
216
+
217
+ json_response = response.json()
218
+ if not json_response.get('ok'):
219
+ # يتم إلقاء خطأ Telegram API إذا كان الرد سلبياً
220
+ error_description = json_response.get('description', 'Unknown API Error')
221
+ raise requests.exceptions.HTTPError(
222
+ f"Telegram API Error via Proxy: {error_description}",
223
+ response=response
224
+ )
225
+ return json_response['result']
226
 
227
+ except requests.exceptions.HTTPError as e:
228
+ error_details = str(e)
229
+ log.error(f"Proxy/Telegram HTTP Error during {method}: {error_details}")
230
+ try:
231
+ error_data = e.response.json()
232
+ error_msg = error_data.get("description", error_details)
233
+ except:
234
+ error_msg = error_details
235
+
236
+ if 'unauthorized' in error_msg.lower() or 'forbidden' in error_msg.lower():
237
+ raise RuntimeError(f"فشل مصادقة Telegram (عبر الجسر): {error_msg}. تأكد من صحة TG_BOT_TOKEN في الجسر.")
238
+ else:
239
+ raise RuntimeError(f"خطأ في جلب البيانات عبر الجسر ({method}): {error_msg}.")
240
+ except Exception as e:
241
+ log.error(f"An unexpected error occurred during proxy fetch: {e}")
242
+ raise RuntimeError(f"خطأ غير متوقع في الاتصال بالجسر: {e}.")
243
+
244
+
245
+ # --- 1. جلب معلومات القناة الأساسية (getChat) ---
246
+ chat_info_data = await fetch_via_proxy(
247
+ "getChat",
248
+ data={"chat_id": TG_CHANNEL}
249
+ )
250
+
251
+ # --- 2. جلب المشرفين (getChatAdministrators) ---
252
+ admins_list = await fetch_via_proxy(
253
+ "getChatAdministrators",
254
+ data={"chat_id": TG_CHANNEL}
255
+ )
256
+
257
+ admins_count = len(admins_list)
258
+
259
+ # تحويل البيانات إلى تنسيق موحد للتحليل
260
+ stats = {
261
+ "chat_id": chat_info_data.get('id'),
262
+ "title": chat_info_data.get('title'),
263
+ "members": chat_info_data.get('members_count', 'N/A'),
264
+ "admins_count": admins_count,
265
+ "description": chat_info_data.get('description'),
266
+ "date": datetime.utcnow().isoformat(),
267
+ }
268
+
269
+ log.info(f"Successfully fetched stats (via proxy) for channel {stats['title']} with {stats['members']} members.")
270
+ return [stats]
271
 
272
 
273
  # ---------------- Main Analysis Pipeline ----------------
 
396
  """Synchronous wrapper to run the async job in the scheduler."""
397
  log.info("Running scheduled analysis job via Gradio wrapper...")
398
  try:
 
399
  result = asyncio.run(run_analysis_pipeline())
400
  log.info(f"Scheduled job completed. Status: {result.get('status')}")
401
  except Exception as e:
 
409
  gr.Markdown("# 🤖 وكيل تحليل قناة Telegram (Webhook/Scheduled)")
410
  gr.Markdown(f"**حالة الخدمة:** {STATUS_MESSAGE}")
411
  gr.Markdown(f"**القناة المستهدفة:** `{TG_CHANNEL}`")
412
+ gr.Markdown(f"**جسر Replit:** `{REPLIT_PROXY_URL}`")
413
  gr.Markdown("---")
414
 
415
  with gr.Tab("تشغيل التحليل يدوياً"):
 
482
  # وضع Webhook
483
  log.info(f"Setting Webhook URL to: {WEBHOOK_URL}")
484
  try:
 
485
  application.bot.set_webhook(url=WEBHOOK_URL)
486
 
487
  log.info(f"Starting Webhook server on {LISTEN_ADDRESS}:{WEBHOOK_PORT}...")
 
488
  url_path = WEBHOOK_URL.split('/')[-1] if WEBHOOK_URL.count('/') > 2 else ""
489
 
 
490
  application.run_webhook(
491
  listen=LISTEN_ADDRESS,
492
  port=WEBHOOK_PORT,
493
  url_path=url_path,
 
494
  )
495
  except Exception as e:
496
  log.error(f"Failed to start Webhook: {e}")