Skip to content

Latest commit

 

History

History
260 lines (215 loc) · 24.3 KB

File metadata and controls

260 lines (215 loc) · 24.3 KB

VK-бот уведомлений о заказах Kwork, FL.ru и Profi.ru

Бот просматривает общие ленты проектов Kwork и FL.ru во всех категориях. Сначала бесплатный локальный фильтр отбирает карточки по широкому набору ключевых слов, затем GigaChat оценивает их по контексту. Подходящие новые проекты отправляются личным сообщением от сообщества VK.

В диалоге постоянно доступна нижняя callback-панель с разделами «Настройки», «Статистика» и «Отклики». Нажатия не создают сообщения от имени пользователя, а переключение нижней клавиатуры происходит через сразу удаляемое невидимое сообщение. Навигационные подписи вроде «Выберите действие» и «Настройки уведомлений» в диалог не попадают. Статистика и отклики используют не более одной видимой информационной панели: при переходе старая панель удаляется. Настройки разделены на источники уведомлений, фильтры проектов и AI-тексты. Для каждой биржи уведомления можно отключить независимо. В VK также настраиваются минимальный AI-балл и минимальный известный бюджет. Проекты без указанного бюджета не отбрасываются. Значения сохраняются в базе и переживают перезапуск. Статистика показывает число проектов, признанных подходящими после AI-оценки, и отдельное число отклонённых AI за 24 часа, 7 и 30 дней. Кнопка «Очистить чат» в настройках удаляет из диалога старые сообщения бота, не затрагивая сообщения пользователя и локальную историю проектов в базе данных. В статистике отображается дата начала отсчёта, а красная кнопка «Очистить статистику» переносит точку отсчёта на текущий момент, не удаляя историю просмотренных проектов и откликов.

Время публикации выводится без секунд в часовом поясе МСК+2 (UTC+5). Подпись часового пояса в самом сообщении не показывается. Автоматические уведомления отправляются только для проектов не старше 24 часов; старые карточки и карточки без даты молча пропускаются.

У каждой карточки есть кнопка «Откликнулся». После нажатия она становится зелёной с галочкой; повторное нажатие отменяет выбор без отдельного сообщения. Раздел «Отклики» показывает сводные счётчики и до 8 активных откликов в той же панели. У каждого проекта прямо в списке есть кнопки «Открыть», «Написал» и «Другой»: статус меняется одним нажатием без перехода в карточку. «Другой» убирает проект из активного списка, а «Написал» оставляет его и подсвечивается зелёным.

Как отбираются проекты

Kwork получает общую выдачу через API мобильного приложения с параметром all, а FL.ru читает общую HTML-ленту заказов /projects/?kind=1 без вакансий и конкурсов. Обе площадки обходятся постранично: максимум 10 страниц или до страницы, на которой все распознанные проекты старше 24 часов.

До обращения к GigaChat название, описание и категория проекта проверяются локально. Фильтр учитывает русские словоформы и варианты написания следующих широких групп:

  • сайт, веб, лендинг, интернет-магазин;
  • дизайн, редизайн, интерфейс, UI/UX;
  • Figma, макет, прототип;
  • Tilda и Zero Block.

Фильтр намеренно пропускает сомнительные совпадения: окончательное решение принимает AI по контексту проекта и профилю исполнителя. Категория площадки сохраняется, но не ограничивает выдачу.

AI отбирает полноценный дизайн сайтов, страниц, мобильных приложений и интерфейсов. Создание готового сайта допускается только при явно выбранной Tilda. Заказы на email-письма, отдельные блоки и мелкие правки, а также разработка сайтов под ключ вне Tilda отклоняются. Общее «сделать сайт» без подтверждения отдельного дизайна или Tilda не считается подходящим. При этом дизайн сайта под любую CMS подходит, если разработку выполняет другой исполнитель.

Новые проекты оцениваются по текущей версии промпта и профиля. Уже отправленные уведомления повторно не рассылаются. При редактировании файлов локально требуется перезапуск бота; замена через «Настройки → AI-тексты» применяется сразу.

Profi.ru авторизуется в кабинете специалиста и использует сохранённый фильтр аккаунта. Перед первым API-запросом бот запускает headless Chromium и сохраняет живую страницу кабинета на всё время работы. Фоновые циклы используют эту сессию последовательно. При закрытии браузера или ошибке запроса сессия пересоздаётся со свежим входом, а при остановке бота браузер закрывается. Cookies и browser-state не экспортируются в файлы проекта. Бот обходит выдачу по cursor-пагинации, извлекает как обычные карточки, так и заказы из каруселей, объединяет повторения по ID и передаёт их в тот же AI-процесс, что и другие биржи. Поэтому локальный фильтр ключевых слов для Profi.ru не применяется: набор заказов определяется услугами аккаунта, например:

  • Landing page
  • Веб-дизайн
  • Макет сайта
  • Создание сайта на Tilda
  • Создание сайтов

Повторяющиеся карточки объединяются по ID проекта, поэтому сообщение придёт один раз.

Настройка VK

  1. Создайте сообщество VK и включите в нем сообщения.
  2. В настройках API сообщества создайте ключ доступа с правом на сообщения.
  3. Напишите сообществу любое сообщение от своего аккаунта. Без этого сообщество не сможет начать личный диалог.
  4. Узнайте числовой ID своего пользователя VK.
  5. В настройках сообщества откройте Сообщения → Настройки для бота и включите Возможности ботов. Без этого VK отклоняет сообщения с клавиатурой.
  6. Откройте Работа с API → Long Poll API и включите Long Poll. Бот автоматически включает события Входящие сообщения и Нажатие на callback-кнопку.

Команда /menu повторно показывает панель, если она была скрыта в клиенте VK. Бот пытается сразу удалить само сообщение /menu, чтобы оно не оставалось в диалоге. Если возможности ботов были включены уже после запуска контейнера, отправьте /menu — перезапускать бот не требуется.

Запуск

cp .env.example .env

Заполните в .env:

  • VK_GROUP_TOKEN — ключ сообщества;
  • VK_USER_ID — ваш числовой ID;
  • KWORK_LOGIN и KWORK_PASSWORD — вход в аккаунт Kwork.
  • PROFI_LOGIN и PROFI_PASSWORD — парольный вход в кабинет специалиста Profi.ru; укажите обе переменные либо оставьте обе пустыми, чтобы отключить источник.
  • GIGACHAT_CREDENTIALS — ключ авторизации проекта GigaChat API;
  • AI_ENABLED=true — включить AI-фильтрацию и генерацию откликов.

AI-конфигурация разделена по задачам:

  • config/prompts/project_filter.txt — единственный источник критериев поиска для Lite;
  • config/freelancer_profile.txt — факты о навыках исполнителя, только для откликов;
  • config/portfolio.json — кейсы: id, name, product, work, platform, url;
  • config/prompts/response_writer.txt — стиль и правила откликов.

Все четыре файла доступны в Настройки → AI-тексты: /set filter, /set profile, /set portfolio, /set response. Новый текст передавайте со следующей строки либо UTF-8 вложением .txt/.json. Изменения применяются сразу, предыдущий файл сохраняется в .bak. Портфолио проверяется перед записью. Каталог ./config подключён к Docker-контейнеру. Пути можно переопределить через AI_FILTER_PROMPT_PATH, AI_PROFILE_PATH, AI_PORTFOLIO_PATH, AI_RESPONSE_PROMPT_PATH.

GIGACHAT_FILTER_MODEL — модель отбора (GigaChat-2 Lite по умолчанию). GIGACHAT_RESPONSE_MODEL — модель откликов (GigaChat-2-Max по умолчанию). Lite возвращает decision (accept, reject, unclear), evidence, reason, summary. Только accept отправляется в VK; остальные решения сохраняются без уведомления. Цитата для accept должна присутствовать в исходном названии/описании. Пустое или обрезанное описание не позволяет принять проект. Эта проверка не доказывает смысловую релевантность цитаты. Бюджет проверяется отдельно. AI_MIN_SCORE и сохранённый порог больше не управляют отбором. Команда /score объясняет переход на решения. Числовые поля в базе сохранены для совместимости с историей: у новых записей это технические 100/0, а не оценка уверенности модели. После обновления старые записи получают пустые decision/evidence; доступные для обработки проекты переоцениваются по новой версии правил. Уже просмотренные публикации заново не рассылаются.

По умолчанию AI_VERIFY_ACCEPTED=true: только кандидаты accept от Lite независимо перепроверяются моделью откликов (Max по умолчанию), без передачи ей решения и объяснения Lite. Это расходует дополнительные токены Max, но не тратит их на отсеянные Lite проекты. При ошибке проверяющей модели проект не отправляется и остаётся для повторной обработки. Если Lite недоступен, после повторов используется модель откликов без дублирующей проверки. При одинаковых моделях второй запрос также не выполняется. AI_VERIFY_ACCEPTED=false отключает смысловую перепроверку; проверка цитаты сохраняется. Отклик создаётся Max только по нажатию «Написать отклик». В запрос передаются исходный заказ, короткий профиль и до шести кейсов-кандидатов, отобранных по типу продукта, тематическим совпадениям и платформе. Модель выбирает обычно 1–2 уместных примера; нерелевантные ссылки добавлять не требуется. Порядок кейсов не считается датой создания. Роль, платформа и результат кейса не выводятся из URL и не придумываются.

Модель отклика возвращает JSON body/case_ids. URL ей не передаются: бот сам вставляет точные ссылки и подписи из каталога перед последним абзацем. В VK приходит обычный текст. Неизвестный ID, пустой ответ, ссылка или описание собственных кейсов в body, отдельные ложные утверждения об изучении материалов или завершение по лимиту вызывают одну попытку исправления. Повторно некорректный отклик не сохраняется и не показывается. Эти проверки не подтверждают доступность сайтов и не выявляют все возможные смысловые ошибки. Бот отправляет чистый текст отдельным сообщением, чтобы его можно было скопировать целиком. Готовый отклик сохраняется в истории проекта. Под ним доступны кнопки «Другой вариант», «Короче», «Деловой», «Более живой» и «Добавить вопрос». Новый вариант заменяет текст в том же сообщении и сохраняется как текущий отклик проекта; каждое нажатие обращается к GigaChat и расходует токены. Карточка не отправляется, пока AI не смог выдать оценку. При временной ошибке API проект остаётся непомеченным и повторно проверяется в следующем цикле. Это исключает появление карточек без краткого описания задачи и не теряет проект после единичного сбоя. Если заказчик перезапускает проект на Kwork и тот же ID снова появляется в общей ленте с новой датой публикации, бот считает это новой публикацией: повторно проверяет её через AI и при соответствии фильтрам снова отправляет карточку. Обычные опросы одной и той же публикации дублей не создают.

Затем:

docker compose up -d --build
docker compose logs -f bot

Отдельная проверка ключа и защищённого соединения с GigaChat:

docker compose run --rm bot gigachat-check

Проверка входа в Profi.ru и чтения сохранённой выдачи без отправки сообщений в VK:

docker compose build bot
docker compose run --rm bot profi-check --check-reauth --check-recovery

Команда проверяет начальную загрузку и два повторных цикла с паузой 180 секунд. --check-reauth удаляет cookies только диагностической сессии и проверяет повторный вход. --check-recovery дополнительно закрывает только диагностический браузер и проверяет автоматический запуск и вход заново. В конце выводятся число карточек и ссылка на самую свежую. VK-сообщения не отправляются, AI не вызывается, база не изменяется. Это проверка источника; AI-отбор и доставка уведомлений в VK проверяются отдельно. Для быстрой проверки входа: profi-check --cycles 0. Пауза настраивается через --interval (минимум 60 секунд). Если Profi.ru запросит SMS, captcha или другое дополнительное подтверждение, команда завершится ошибкой: такой вход автоматически не поддерживается, а сессия вашего обычного браузера не переносится в бот.

Локальный запуск без Docker:

python3.12 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
python -m playwright install chromium
freelance-bot

По умолчанию опрос идет раз в 3 минуты. Первый запуск запоминает текущие карточки и ничего не отправляет, чтобы не присылать старые заказы. Для теста можно временно установить SEND_EXISTING_ON_FIRST_RUN=true.

Важные ограничения

  • Kwork не предоставляет официальный публичный API для этой задачи. Используется актуальная неофициальная библиотека, работающая с API мобильного приложения; после изменений Kwork интеграции может понадобиться обновление.
  • FL.ru читается из общей HTML-ленты. После изменений разметки площадки CSS-селекторы парсера могут потребовать обновления.
  • Profi.ru не предоставляет публичный API для такой интеграции. Используется запрос кабинета специалиста с его сохранённым фильтром; после изменений Profi.ru интеграцию может потребоваться обновить. После истечения cookies бот автоматически входит заново. При неверном пароле или запросе дополнительного подтверждения повторные попытки выполняются с растущей паузой до часа, чтобы не создавать частые неудачные входы. В одном запросе допускаются максимум два парольных входа; успешный обмен токена сам по себе не сбрасывает паузу — это делает только успешное чтение защищённой доски заказов.
  • Не ставьте интервал меньше минуты: это повышает риск антибот-ограничений площадок.

Проверка качества AI

eval/projects.json — 20 синтетических пограничных заказов с ожидаемыми решениями, не замена пользовательской разметке реальных проектов. Для реальной оценки соберите 50–100 заказов с полями id, title, description, expected (accept/reject/unclear). Проверка использует платный API, не отправляет сообщения VK и не изменяет базу бота:

python -m freelance_bot.evaluate_ai --live --responses --output data/eval-current.json

--dataset задаёт другой набор; --limit ограничивает число заказов (по умолчанию 20). --responses также создаёт отклики для ожидаемо подходящих заказов. Для 15 отдельных сценариев откликов:

python -m freelance_bot.evaluate_ai --live --responses-only --dataset eval/writer_projects.json --limit 15 --output data/eval-writer.json

Отчёт содержит решения, цитаты, причины, фактическую модель, версию правил, число ложных допусков и потерь, precision/recall (null при отсутствии знаменателя). При инфраструктурной ошибке пакет останавливается. Сохраните отчёты до и после изменения промпта на одном наборе; сравнивайте обе метрики. Отклики проверяйте вручную: факты, ответы на вопросы клиента, уместность кейсов, обоснованность следующего шага и объём необходимой правки. Положительный результат unit-тестов проверяет код, но не подтверждает улучшение качества GigaChat.

После обновления кода пересоздайте контейнер: docker compose up -d --build. Файлы config должны обновиться вместе с кодом: старый промпт с полем score несовместим с новой схемой решения. База мигрирует при запуске, старые отклики сохраняются.