feat: add subscribtion scheduler with ai, pagination

This commit is contained in:
Faynot
2026-03-29 11:25:31 +03:00
parent 1db524f757
commit 164acd6307
16 changed files with 688 additions and 358 deletions

89
scheduler.py Normal file
View 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)