AI Update: تغییرات جایگزینی آیدی خام با نام را اعمال کن

This commit is contained in:
Antigravity Bot
2026-08-30 16:37:04 +03:30
parent e8d0bd71cd
commit 08010ebec4
3 changed files with 96 additions and 17 deletions
+44 -11
View File
@@ -634,7 +634,7 @@ class AdminBotService:
]) ])
return buttons return buttons
def _format_raw_post_caption(self, post: Post) -> str: async def _format_raw_post_caption(self, post: Post) -> str:
published_lines = "" published_lines = ""
if post.published_to: if post.published_to:
published_lines = "📤 <b>وضعیت ارسال به کانال‌های مقصد:</b>\n" published_lines = "📤 <b>وضعیت ارسال به کانال‌های مقصد:</b>\n"
@@ -654,8 +654,27 @@ class AdminBotService:
tag_line = f"🏷 <b>موضوع:</b> #{post.subject}\n\n" if getattr(post, "subject", None) else "" tag_line = f"🏷 <b>موضوع:</b> #{post.subject}\n\n" if getattr(post, "subject", None) else ""
if post.source_channel_id <= -900000000:
site_id = abs(post.source_channel_id + 900000000)
site = await self.repo.get_source_website_by_id(site_id)
if site and site.name:
source_label = f"🌐 وبسایت <b>{site.name}</b>"
elif site and site.url:
source_label = f"🌐 وبسایت <b>{site.url}</b>"
else:
source_label = f"🌐 وبسایت <code>#{site_id}</code>"
else:
src = await self.repo.get_source_by_channel_id(post.source_channel_id)
if src and src.title:
user_part = f" (@{src.username})" if src.username else ""
source_label = f"📢 کانال <b>{src.title}</b>{user_part}"
elif src and src.username:
source_label = f"📢 کانال @<b>{src.username}</b>"
else:
source_label = f"کانال <code>{post.source_channel_id}</code>"
caption = ( caption = (
f"📥 <b>پست جدید از مبدا (<code>{post.source_channel_id}</code>):</b>\n\n" f"📥 <b>پست جدید از {source_label}:</b>\n\n"
f"{rejection_line}" f"{rejection_line}"
f"{published_lines}" f"{published_lines}"
f"{tag_line}" f"{tag_line}"
@@ -693,7 +712,7 @@ class AdminBotService:
targets = await self.repo.get_active_targets() targets = await self.repo.get_active_targets()
keyboard = self._build_raw_post_keyboard(post, targets) keyboard = self._build_raw_post_keyboard(post, targets)
caption = self._format_raw_post_caption(post) caption = await self._format_raw_post_caption(post)
if refresh_only: if refresh_only:
# Update the card that already exists instead of posting a second one. # Update the card that already exists instead of posting a second one.
@@ -1236,10 +1255,12 @@ class AdminBotService:
st_icon = "🛑 متوقف (Paused)" if is_paused else "🟢 فعال و در حال کار (Running)" st_icon = "🛑 متوقف (Paused)" if is_paused else "🟢 فعال و در حال کار (Running)"
pause_btn_text = "▶️ راه‌اندازی سیستم" if is_paused else "🛑 توقف سیستم" pause_btn_text = "▶️ راه‌اندازی سیستم" if is_paused else "🛑 توقف سیستم"
pause_cb = "sys_resume" if is_paused else "sys_pause" pause_cb = "sys_resume" if is_paused else "sys_pause"
def_adm = await self.repo.get_default_admin_channel()
adm_label = f"<b>{def_adm.title}</b> (<code>{def_adm.channel_id}</code>)" if (def_adm and def_adm.title) else (f"<code>{self.review_channel_id}</code>" if self.review_channel_id else "تعریف‌نشده")
text = ( text = (
f"⚙️ <b>بخش کنترل و مدیریت سیستم (System Hub):</b>\n\n" f"⚙️ <b>بخش کنترل و مدیریت سیستم (System Hub):</b>\n\n"
f"• ⚡️ <b>وضعیت کنونی سیستم:</b> <b>{st_icon}</b>\n" f"• ⚡️ <b>وضعیت کنونی سیستم:</b> <b>{st_icon}</b>\n"
f"• 📋 <b>کانال نظارت ادمین:</b> <code>{self.review_channel_id}</code>\n\n" f"• 📋 <b>کانال نظارت ادمین:</b> {adm_label}\n\n"
f"<i>عملیات مورد نظر را انتخاب کنید:</i>" f"<i>عملیات مورد نظر را انتخاب کنید:</i>"
) )
buttons = [ buttons = [
@@ -1274,7 +1295,9 @@ class AdminBotService:
is_def = (source.admin_channel_id is None) is_def = (source.admin_channel_id is None)
def_mark = "" if is_def else "" def_mark = "" if is_def else ""
buttons.append([Button.inline(f"{def_mark}⚙️ پیش‌فرض سیستم ({self.review_channel_id})", data=f"src_set_adm:{source.id}:none")]) def_adm = await self.repo.get_default_admin_channel()
def_name = f" ({def_adm.title})" if (def_adm and def_adm.title) else (f" ({self.review_channel_id})" if self.review_channel_id else "")
buttons.append([Button.inline(f"{def_mark}⚙️ پیش‌فرض سیستم{def_name}", data=f"src_set_adm:{source.id}:none")])
buttons.append([Button.inline("➕ افزودن کانال ادمین جدید", data=f"src_add_adm:{source.id}")]) buttons.append([Button.inline("➕ افزودن کانال ادمین جدید", data=f"src_add_adm:{source.id}")])
buttons.append([Button.inline("🔙 بازگشت به تنظیمات کانال مبدا", data=f"src_view:{source.id}")]) buttons.append([Button.inline("🔙 بازگشت به تنظیمات کانال مبدا", data=f"src_view:{source.id}")])
return text, buttons return text, buttons
@@ -1299,7 +1322,9 @@ class AdminBotService:
is_def = (site.admin_channel_id is None) is_def = (site.admin_channel_id is None)
def_mark = "" if is_def else "" def_mark = "" if is_def else ""
buttons.append([Button.inline(f"{def_mark}⚙️ پیش‌فرض سیستم ({self.review_channel_id})", data=f"web_set_adm:{site.id}:none")]) def_adm = await self.repo.get_default_admin_channel()
def_name = f" ({def_adm.title})" if (def_adm and def_adm.title) else (f" ({self.review_channel_id})" if self.review_channel_id else "")
buttons.append([Button.inline(f"{def_mark}⚙️ پیش‌فرض سیستم{def_name}", data=f"web_set_adm:{site.id}:none")])
buttons.append([Button.inline("➕ افزودن کانال ادمین جدید", data=f"web_add_adm:{site.id}")]) buttons.append([Button.inline("➕ افزودن کانال ادمین جدید", data=f"web_add_adm:{site.id}")])
buttons.append([Button.inline("🔙 بازگشت به تنظیمات وبسایت", data=f"web_view:{site.id}")]) buttons.append([Button.inline("🔙 بازگشت به تنظیمات وبسایت", data=f"web_view:{site.id}")])
return text, buttons return text, buttons
@@ -1432,7 +1457,9 @@ class AdminBotService:
except Exception as e: except Exception as e:
logger.warning(f"Error deleting chunk from channel {ch_id}: {e}") logger.warning(f"Error deleting chunk from channel {ch_id}: {e}")
summary = f"🗑 <b>پیام‌های کانال نظارت <code>{ch_id}</code> پاکسازی شدند:</b>\n\n• 🗑 پیام‌های حذف‌شده از تلگرام: <b>{deleted_tg_count}</b>\n• 🗂 پست‌های بایگانی‌شده در سیستم: <b>{cleared_db_count}</b>" adm = await self.repo.get_admin_channel_by_telegram_id(ch_id)
ch_name = f"«{adm.title}»" if adm and adm.title else f"<code>{ch_id}</code>"
summary = f"🗑 <b>پیام‌های کانال نظارت {ch_name} پاکسازی شدند:</b>\n\n• 🗑 پیام‌های حذف‌شده از تلگرام: <b>{deleted_tg_count}</b>\n• 🗂 پست‌های بایگانی‌شده در سیستم: <b>{cleared_db_count}</b>"
return deleted_tg_count, cleared_db_count, summary return deleted_tg_count, cleared_db_count, summary
@@ -1693,10 +1720,13 @@ class AdminBotService:
me = await self.collector.client.get_me() me = await self.collector.client.get_me()
userbot_status = f"🟢 آنلاین ({me.first_name})" userbot_status = f"🟢 آنلاین ({me.first_name})"
def_adm = await self.repo.get_default_admin_channel()
adm_label = f"<b>{def_adm.title}</b> (<code>{def_adm.channel_id}</code>)" if (def_adm and def_adm.title) else (f"<code>{self.review_channel_id}</code>" if self.review_channel_id else "تعریف‌نشده")
welcome_text = ( welcome_text = (
"👋 <b>به پنل مدیریت سیستم هوشمند کپی‌کار خوش آمدید!</b>\n\n" "👋 <b>به پنل مدیریت سیستم هوشمند کپی‌کار خوش آمدید!</b>\n\n"
f"• 🤖 <b>وضعیت ربات جمع‌آوری‌کننده:</b> {userbot_status}\n" f"• 🤖 <b>وضعیت ربات جمع‌آوری‌کننده:</b> {userbot_status}\n"
f"• 📋 <b>شناسه کانال ادمین‌ها:</b> <code>{self.review_channel_id}</code>\n\n" f"• 📋 <b>کانال نظارت ادمین:</b> {adm_label}\n\n"
"برای مدیریت کانال‌ها از دکمه‌های زیر استفاده کنید:" "برای مدیریت کانال‌ها از دکمه‌های زیر استفاده کنید:"
) )
menu = await self.get_menu() menu = await self.get_menu()
@@ -3250,10 +3280,13 @@ class AdminBotService:
me = await self.collector.client.get_me() me = await self.collector.client.get_me()
userbot_status = f"🟢 آنلاین ({me.first_name})" userbot_status = f"🟢 آنلاین ({me.first_name})"
def_adm = await self.repo.get_default_admin_channel()
adm_label = f"<b>{def_adm.title}</b> (<code>{def_adm.channel_id}</code>)" if (def_adm and def_adm.title) else (f"<code>{self.review_channel_id}</code>" if self.review_channel_id else "تعریف‌نشده")
welcome_text = ( welcome_text = (
"👋 <b>منوی اصلی سیستم هوشمند کپی‌کار:</b>\n\n" "👋 <b>منوی اصلی سیستم هوشمند کپی‌کار:</b>\n\n"
f"• 🤖 <b>وضعیت ربات جمع‌آوری‌کننده:</b> {userbot_status}\n" f"• 🤖 <b>وضعیت ربات جمع‌آوری‌کننده:</b> {userbot_status}\n"
f"• 📋 <b>شناسه کانال ادمین‌ها:</b> <code>{self.review_channel_id}</code>\n\n" f"• 📋 <b>کانال نظارت ادمین:</b> {adm_label}\n\n"
"برای مدیریت بخش‌های مختلف از دکمه‌های زیر استفاده کنید:" "برای مدیریت بخش‌های مختلف از دکمه‌های زیر استفاده کنید:"
) )
buttons = get_persian_inline_hub_menu() buttons = get_persian_inline_hub_menu()
@@ -3667,7 +3700,7 @@ class AdminBotService:
updated_post = await self.repo.get_post_by_id(post_id) updated_post = await self.repo.get_post_by_id(post_id)
targets = await self.repo.get_active_targets() targets = await self.repo.get_active_targets()
new_caption = self._format_raw_post_caption(updated_post) new_caption = await self._format_raw_post_caption(updated_post)
new_buttons = self._build_raw_post_keyboard(updated_post, targets) new_buttons = self._build_raw_post_keyboard(updated_post, targets)
await event.edit( await event.edit(
@@ -3689,7 +3722,7 @@ class AdminBotService:
return return
targets = await self.repo.get_active_targets() targets = await self.repo.get_active_targets()
caption = self._format_raw_post_caption(post) caption = await self._format_raw_post_caption(post)
buttons = self._build_raw_post_keyboard(post, targets) buttons = self._build_raw_post_keyboard(post, targets)
await event.edit(caption, parse_mode="html", buttons=buttons) await event.edit(caption, parse_mode="html", buttons=buttons)
+7 -6
View File
@@ -35,13 +35,14 @@ class ScrapeResult:
duplicates: int = 0 duplicates: int = 0
error: Optional[str] = None error: Optional[str] = None
def summary_fa(self, channel_id: int) -> str: def summary_fa(self, channel_id: int, channel_title: Optional[str] = None) -> str:
name_label = f"<b>{channel_title}</b>" if channel_title else f"<code>{channel_id}</code>"
if self.error: if self.error:
return f"❌ خطا در دریافت پست‌های کانال <code>{channel_id}</code>: {self.error}" return f"❌ خطا در دریافت پست‌های کانال {name_label}: {self.error}"
header = ( header = (
f"✅ <b>{self.collected}</b> پست جدید از <code>{channel_id}</code> دریافت و به کانال ادمین ارسال شد." f"✅ <b>{self.collected}</b> پست جدید از کانال {name_label} دریافت و به کانال ادمین ارسال شد."
if self.collected if self.collected
else f"️ هیچ پست <b>جدیدی</b> در <code>{channel_id}</code> پیدا نشد." else f"️ هیچ پست <b>جدیدی</b> در کانال {name_label} پیدا نشد."
) )
return ( return (
f"{header}\n\n" f"{header}\n\n"
@@ -388,13 +389,13 @@ class CollectorService:
result.already_stored += 1 result.already_stored += 1
if progress_callback: if progress_callback:
await progress_callback(result.summary_fa(channel_id)) await progress_callback(result.summary_fa(channel_id, source_title))
return result return result
except Exception as e: except Exception as e:
await log_exception("collector.scrape_history", e, {"channel_id": channel_id, "limit": limit}) await log_exception("collector.scrape_history", e, {"channel_id": channel_id, "limit": limit})
result.error = str(e) result.error = str(e)
if progress_callback: if progress_callback:
await progress_callback(result.summary_fa(channel_id)) await progress_callback(result.summary_fa(channel_id, source_title))
return result return result
async def stop(self): async def stop(self):
+45
View File
@@ -0,0 +1,45 @@
import pytest
from unittest.mock import AsyncMock, MagicMock
from services.collector import ScrapeResult
from services.admin_bot import AdminBotService
from db.models import Post, SourceChannel, SourceWebsite
def test_collector_summary_fa_with_title():
res = ScrapeResult(scanned=10, collected=5, already_stored=3, duplicates=2)
summary = res.summary_fa(channel_id=-100123456, channel_title="کانال خبری فناوری")
assert "کانال خبری فناوری" in summary
assert "<code>-100123456</code>" not in summary
def test_collector_summary_fa_fallback_to_id():
res = ScrapeResult(scanned=10, collected=0, already_stored=10, duplicates=0)
summary = res.summary_fa(channel_id=-100123456, channel_title=None)
assert "-100123456" in summary
@pytest.mark.asyncio
async def test_admin_bot_format_raw_post_caption_telegram_channel():
repo = MagicMock()
repo.get_source_by_channel_id = AsyncMock(return_value=SourceChannel(
id=1, channel_id=-100123456, username="tech_news", title="اخبار روز تکنولوژی"
))
bot = AdminBotService(repo=repo, ai_processor=MagicMock(), queue=MagicMock())
post = Post(id=1, source_channel_id=-100123456, source_message_id=10, raw_text="متن تست پست")
caption = await bot._format_raw_post_caption(post)
assert "اخبار روز تکنولوژی" in caption
assert "@tech_news" in caption
@pytest.mark.asyncio
async def test_admin_bot_format_raw_post_caption_website():
repo = MagicMock()
pseudo_id = -900000005
repo.get_source_website_by_id = AsyncMock(return_value=SourceWebsite(
id=5, name="دیجیاتو", url="https://digiato.com"
))
bot = AdminBotService(repo=repo, ai_processor=MagicMock(), queue=MagicMock())
post = Post(id=2, source_channel_id=pseudo_id, source_message_id=1, raw_text="خبر جدید وبسایت")
caption = await bot._format_raw_post_caption(post)
assert "دیجیاتو" in caption
assert "وبسایت" in caption