feat(workflow): implement target channel personalities, raw review cards, on-demand AI rewrites and multi-target dispatch
This commit is contained in:
+28
-23
@@ -6,9 +6,8 @@ from telethon.errors import SessionPasswordNeededError
|
||||
from telethon.tl.types import MessageMediaPhoto, MessageMediaDocument
|
||||
from db.repository import Repository
|
||||
from core.dedup import compute_content_hash, compute_file_hash
|
||||
from services.ai_processor import AIProcessor
|
||||
from core.queue import RedisQueue
|
||||
from core.metrics import COLLECTED_POSTS_TOTAL
|
||||
from core.metrics import COLLECTED_POSTS_TOTAL, SOURCE_ACTIVITY_TOTAL
|
||||
from core.proxy import get_telegram_proxy
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -20,7 +19,7 @@ class CollectorService:
|
||||
def __init__(
|
||||
self,
|
||||
repo: Repository,
|
||||
ai_processor: AIProcessor,
|
||||
on_post_received: Optional[Callable[[int], Awaitable[None]]] = None,
|
||||
queue: Optional[RedisQueue] = None,
|
||||
api_id: Optional[int] = None,
|
||||
api_hash: Optional[str] = None,
|
||||
@@ -28,7 +27,7 @@ class CollectorService:
|
||||
session_name: Optional[str] = None,
|
||||
):
|
||||
self.repo = repo
|
||||
self.ai_processor = ai_processor
|
||||
self.on_post_received = on_post_received
|
||||
self.queue = queue
|
||||
self.api_id = api_id or int(os.getenv("API_ID", "0"))
|
||||
self.api_hash = api_hash or os.getenv("API_HASH", "")
|
||||
@@ -56,14 +55,14 @@ class CollectorService:
|
||||
sent = await self.client.send_code_request(self.phone)
|
||||
self.phone_code_hash = sent.phone_code_hash
|
||||
await notify_fn(
|
||||
f"🔐 <b>Collector Userbot Login Required</b>\n\n"
|
||||
f"A login code was sent to phone <code>{self.phone}</code>.\n\n"
|
||||
f"Please reply with: <code>/code <your_code></code>\n"
|
||||
f"(Or <code>/password <2fa_password></code> if 2FA is enabled)."
|
||||
f"🔐 <b>نیاز به ورود ربات جمعآوریکننده</b>\n\n"
|
||||
f"کد تایید تلگرام به شماره <code>{self.phone}</code> ارسال شد.\n\n"
|
||||
f"لطفا با دستور زیر پاسخ دهید:\n"
|
||||
f"<code>/code 12345</code>"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send login code request: {e}")
|
||||
await notify_fn(f"❌ Failed to request login code: {e}")
|
||||
await notify_fn(f"❌ خطا در ارسال کد ورود: {e}")
|
||||
return False
|
||||
|
||||
async def submit_code(self, code: str) -> str:
|
||||
@@ -75,20 +74,20 @@ class CollectorService:
|
||||
await self.client.sign_in(phone=self.phone, code=code, phone_code_hash=self.phone_code_hash)
|
||||
me = await self.client.get_me()
|
||||
self._register_handlers()
|
||||
return f"✅ Logged in successfully as <b>{me.first_name}</b> (@{me.username or 'none'}). Collector is now active!"
|
||||
return f"✅ ورود موفقیتآمیز بود! حساب فعال: <b>{me.first_name}</b> (@{me.username or 'ندارد'})."
|
||||
except SessionPasswordNeededError:
|
||||
return "🔐 <b>Two-Factor Authentication (2FA) is enabled.</b> Please send: <code>/password <your_2fa_password></code>"
|
||||
return "🔐 <b>رمز دو مرحلهای فعال است.</b> لطفا با این دستور رمز را وارد کنید: <code>/password رمز_عبور</code>"
|
||||
except Exception as e:
|
||||
return f"❌ Login failed: {e}"
|
||||
return f"❌ خطا در ورود: {e}"
|
||||
|
||||
async def submit_password(self, password: str) -> str:
|
||||
try:
|
||||
await self.client.sign_in(password=password)
|
||||
me = await self.client.get_me()
|
||||
self._register_handlers()
|
||||
return f"✅ 2FA Verified! Logged in as <b>{me.first_name}</b> (@{me.username or 'none'}). Collector is now active!"
|
||||
return f"✅ تایید دو مرحلهای موفق بود! حساب فعال: <b>{me.first_name}</b>."
|
||||
except Exception as e:
|
||||
return f"❌ 2FA verification failed: {e}"
|
||||
return f"❌ خطا در تایید رمز دو مرحلهای: {e}"
|
||||
|
||||
def _register_handlers(self):
|
||||
if self._handlers_registered:
|
||||
@@ -141,11 +140,13 @@ class CollectorService:
|
||||
|
||||
if post_id:
|
||||
COLLECTED_POSTS_TOTAL.labels(source_channel_id=str(chat_id)).inc()
|
||||
logger.info(f"Collected new post ID {post_id} from channel {chat_id}")
|
||||
SOURCE_ACTIVITY_TOTAL.labels(channel_id=str(chat_id), title=source.title or 'Unknown').inc()
|
||||
logger.info(f"Collected raw post ID {post_id} from source channel {chat_id}")
|
||||
|
||||
if self.queue:
|
||||
await self.queue.push(post_id)
|
||||
else:
|
||||
await self.ai_processor.process_post(post_id)
|
||||
elif self.on_post_received:
|
||||
await self.on_post_received(post_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Error handling message from {event.chat_id}: {e}", exc_info=True)
|
||||
|
||||
@@ -158,9 +159,11 @@ class CollectorService:
|
||||
"""Scrape historical messages from a source channel."""
|
||||
if not self.client.is_connected() or not await self.client.is_user_authorized():
|
||||
if progress_callback:
|
||||
await progress_callback("❌ Collector Userbot is not authorized. Please log in first.")
|
||||
await progress_callback("❌ ربات متصل نیست. لطفا ابتدا لاگین کنید.")
|
||||
return 0
|
||||
|
||||
source = await self.repo.get_source_by_channel_id(channel_id)
|
||||
source_title = source.title if source else str(channel_id)
|
||||
collected_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
@@ -210,23 +213,25 @@ class CollectorService:
|
||||
if post_id:
|
||||
collected_count += 1
|
||||
COLLECTED_POSTS_TOTAL.labels(source_channel_id=str(channel_id)).inc()
|
||||
logger.info(f"Backfilled historical post ID {post_id} from {channel_id}")
|
||||
SOURCE_ACTIVITY_TOTAL.labels(channel_id=str(channel_id), title=source_title).inc()
|
||||
logger.info(f"Backfilled raw post ID {post_id} from {channel_id}")
|
||||
|
||||
if self.queue:
|
||||
await self.queue.push(post_id)
|
||||
else:
|
||||
await self.ai_processor.process_post(post_id)
|
||||
elif self.on_post_received:
|
||||
await self.on_post_received(post_id)
|
||||
else:
|
||||
skipped_count += 1
|
||||
|
||||
if progress_callback:
|
||||
await progress_callback(
|
||||
f"✅ Scraped <b>{collected_count}</b> new posts from <code>{channel_id}</code> and queued in Redis! (Skipped {skipped_count} existing/empty)."
|
||||
f"✅ تعداد <b>{collected_count}</b> پست جدید از <code>{channel_id}</code> دریافت و در کانال ادمین قرار گرفت! (رد شده تکراری: {skipped_count})."
|
||||
)
|
||||
return collected_count
|
||||
except Exception as e:
|
||||
logger.error(f"Error scraping history from {channel_id}: {e}", exc_info=True)
|
||||
if progress_callback:
|
||||
await progress_callback(f"❌ Error scraping channel <code>{channel_id}</code>: {e}")
|
||||
await progress_callback(f"❌ خطا در دریافت پستهای کانال <code>{channel_id}</code>: {e}")
|
||||
return collected_count
|
||||
|
||||
async def stop(self):
|
||||
|
||||
Reference in New Issue
Block a user