feat: add subscribtion scheduler with ai, pagination
This commit is contained in:
89
scheduler.py
Normal file
89
scheduler.py
Normal file
@@ -0,0 +1,89 @@
|
||||
import asyncio
|
||||
import random
|
||||
import time
|
||||
import html
|
||||
from aiogram import Bot
|
||||
from database import Database
|
||||
from kwork import get_kwork_projects, get_project_details
|
||||
from ai import filter_vacancies_with_ai
|
||||
|
||||
class VacancyScanner:
|
||||
def __init__(self, bot: Bot, db: Database):
|
||||
self.bot = bot
|
||||
self.db = db
|
||||
self.current_page = 1
|
||||
self.last_reset_time = time.time()
|
||||
|
||||
async def start_scanning(self):
|
||||
while True:
|
||||
try:
|
||||
current_time = time.time()
|
||||
if current_time - self.last_reset_time >= 3600:
|
||||
print("--- Прошел час: возврат на 1 страницу ---")
|
||||
self.current_page = 1
|
||||
self.last_reset_time = current_time
|
||||
|
||||
print(f"--- Сканирую страницу {self.current_page} ---")
|
||||
summary_vacancies = await get_kwork_projects(start_page=self.current_page, end_page=self.current_page)
|
||||
|
||||
if not summary_vacancies:
|
||||
print(f"Страница {self.current_page} пуста. Сброс на 1 стр.")
|
||||
self.current_page = 1
|
||||
else:
|
||||
print(f"Найдено {len(summary_vacancies)} вакансий на странице.")
|
||||
users = await self.db.get_all()
|
||||
|
||||
for user in users:
|
||||
user_id = user[1]
|
||||
if not user[2] or not user[3]:
|
||||
print(f"Пропуск пользователя {user_id}: профиль не заполнен.")
|
||||
continue
|
||||
|
||||
# Отбираем новые вакансии
|
||||
new_for_user = []
|
||||
for v in summary_vacancies:
|
||||
if not await self.db.is_vacancy_sent(user_id, v['url']):
|
||||
new_for_user.append(v)
|
||||
|
||||
if not new_for_user:
|
||||
print(f"Для пользователя {user_id} новых вакансий нет.")
|
||||
continue
|
||||
|
||||
print(f"Отправка {len(new_for_user)} вакансий на анализ AI для юзера {user_id}...")
|
||||
user_prefs = f"Сфера: {user[2]}, Стек: {user[3]}, Доп: {user[4]}"
|
||||
|
||||
filtered_vacancies = await filter_vacancies_with_ai(new_for_user, user_prefs)
|
||||
print(f"AI отобрал {len(filtered_vacancies)} релевантных вакансий.")
|
||||
|
||||
for vac in filtered_vacancies:
|
||||
# Получаем детали
|
||||
full_info = await get_project_details(vac['url'])
|
||||
description = full_info['description'] if full_info else vac.get('description', 'Нет описания')
|
||||
|
||||
title = html.escape(vac.get('title', 'Без названия'))
|
||||
price = html.escape(vac.get('price', 'По договоренности'))
|
||||
|
||||
text = (
|
||||
f"🎯 <b>Подходящий проект!</b>\n\n"
|
||||
f"💼 <b>{title}</b>\n"
|
||||
f"💰 <b>Бюджет:</b> {price}\n\n"
|
||||
f"📝 <b>Описание:</b>\n{html.escape(description)}\n\n"
|
||||
f"🔗 <a href='{vac['url']}'>Открыть на Kwork</a>"
|
||||
)
|
||||
|
||||
try:
|
||||
await self.bot.send_message(user_id, text, disable_web_page_preview=True)
|
||||
await self.db.mark_vacancy_as_sent(user_id, vac['url'])
|
||||
await asyncio.sleep(1)
|
||||
except Exception as e:
|
||||
print(f"Ошибка отправки сообщения: {e}")
|
||||
|
||||
self.current_page += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"Критическая ошибка сканера: {e}")
|
||||
await asyncio.sleep(60)
|
||||
|
||||
wait_time = random.uniform(150, 240)
|
||||
print(f"Цикл завершен. Ожидание {wait_time/60:.2f} мин...")
|
||||
await asyncio.sleep(wait_time)
|
||||
Reference in New Issue
Block a user