AAYMA
RU
Войти

EventMatch KZ

Веб-сервис подбирает до трёх подрядчиков для мероприятия из CSV-каталога по городу, дате, формату, категории и бюджету (опционально язык и…

Рабочий MVP
Команда «The Copy Pasters» 13💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: The Copy Pasters
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP

Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор

Суть

Веб-сервис подбирает до трёх подрядчиков для мероприятия из CSV-каталога по городу, дате, формату, категории и бюджету (опционально язык и длительность) и показывает факты профиля, на которых основан выбор. Пользователь может вести личных подрядчиков в Supabase, есть AI-анализ профиля по кнопке.

Как устроено

FastAPI-бэкенд: сначала фильтрует профили по точному городу и категории, исключает занятых на выбранную дату, затем проверяет формат, бюджет, язык и длительность. Прошедшие профили ранжируются по словарному совпадению описания с запросом, близости к бюджету и подходящей длительности; равные оценки упорядочиваются по стабильному ID. Если результатов нет, сервис различает «категории нет в городе» и «кандидаты отсеяны условиями» и показывает причины отсева. OpenAI (по умолчанию gpt-6-luna) вызывается только по кнопке, объясняет факты профиля и не влияет на фильтрацию и порядок; число запросов ограничено 8 в минуту.

Ключевые решения

  • фильтрация по жёстким условиям
  • словарная оценка релевантности
  • ранжирование по близости к бюджету
  • причины отсева
  • Supabase Auth + RLS
  • ограничение частоты запросов

Особенности

Честная пустая выдача: отдельно сообщается, что категории нет в городе, и отдельно — что профили есть, но не прошли условия, с перечнем причин отсева. Синтетические профили и восстановленные города и цены помечаются в интерфейсе.

Стек

Python · FastAPI · Uvicorn · Supabase · PostgreSQL · HTML/CSS/JS · pytest

Модели

gpt-6-luna


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-6f9c6e6e-the-copy-pasters.

README

README.md

EventMatch KZ — подбор event-подрядчиков

Сервис помогает выбрать до трёх подрядчиков из каталога по городу, дате, формату мероприятия, категории и бюджету. Язык и длительность можно задать как дополнительные условия. Рядом с каждым вариантом сервис показывает факты профиля, на которых основан подбор.

Запуск в Windows

Нужен Python 3.10 или новее.

Откройте PowerShell в папке проекта:

py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m uvicorn app:app --reload

Откройте сайт: http://127.0.0.1:8000
Интерактивная документация API: http://127.0.0.1:8000/docs

Чтобы запустить из другой текущей папки, передайте Uvicorn путь к проекту:

$project = "C:\Users\Alimz\Downloads\Telegram Desktop\event_matcher_hackathon\event_matcher"
$python = Join-Path $project ".venv\Scripts\python.exe"
& $python -m uvicorn --app-dir $project app:app --reload

Каталог ищется относительно файлов приложения, поэтому смена текущей папки не меняет источник данных.

Личные подрядчики и ИИ-анализ

Исходный data.csv — общий каталог и не меняется при добавлении профилей. Чтобы пользователь мог войти по email и хранить собственных подрядчиков:

  1. Скопируйте .env.example в .env в корне проекта. Заполните SUPABASE_URL и SUPABASE_PUBLISHABLE_KEY. Приложение использует пользовательский токен Supabase Auth и RLS; SUPABASE_SECRET_KEY ему не нужен.
  2. В Supabase Dashboard откройте SQL Editor, вставьте содержимое supabase/migrations/202609230001_personal_contractors.sql и выполните его.
  3. В Authentication → URL Configuration добавьте разрешённые адреса локального приложения, например http://127.0.0.1:8000/** и http://localhost:8000/**. Если запускаете приложение на другом порту, добавьте его адрес.
  4. В Authentication → Providers → Email включите регистрацию email/пароль. При включённом подтверждении email ссылка из письма возвращает пользователя в приложение.
  5. После изменений .env перезапустите FastAPI.

Пользователь может добавлять, изменять и удалять свои профили. Они участвуют в его подборе и скрыты от других аккаунтов. Общий CSV-каталог остаётся доступным всем.

Чтобы включить анализ профиля по кнопке, добавьте OPENAI_API_KEY в локальный .env. Ключ создаётся в OpenAI API Platform, хранится только на сервере и не должен попадать в браузер, чат или Git. По умолчанию используется gpt-6-luna; модель можно переопределить через OPENAI_MODEL. API оплачивается отдельно от ChatGPT. Настройте лимит расходов и уведомления на стороне OpenAI Platform. Без ключа поиск и карточки продолжают работать.

ИИ вызывается только по кнопке «Анализировать с ИИ», получает факты выбранного профиля и условия поиска без контактных данных, не меняет фильтрацию и порядок результатов. Сервер ограничивает частоту до 8 запросов в минуту на аккаунт или IP.

Проверка

.\.venv\Scripts\python.exe -m pytest -q

Как устроен подбор

  1. Выбираются профили точного города и категории.
  2. Профили, занятые в выбранную дату, исключаются.
  3. Проверяются формат и бюджет, а также заданные язык и длительность. Если профиль не содержит подтверждения для запрошенного языка или длительности, он не считается совпадением.
  4. Подходящие профили ранжируются по совпадению описания с запросом, близости к бюджету и, если задано, подходящей длительности. Одинаковые оценки разрешаются стабильным ID.
  5. На странице показывается до трёх результатов. В объяснениях используются поля профиля и запроса. Синтетические профили, восстановленные города и цены помечаются отдельно.

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

В списке категорий доступны все категории каталога. Те, которых нет в выбранном городе, отмечены рядом с названием; их можно выбрать, чтобы получить отдельное сообщение об отсутствии категории.

Ограничения

  • Общий каталог хранится в data.csv; личные профили — в Supabase Postgres. После изменения .env перезапустите приложение.
  • Релевантность текста вычисляется прозрачным словарным сопоставлением, а не генеративной или семантической моделью.
  • ИИ-анализ поясняет факты профиля и может ошибаться; исходные поля остаются видны рядом для проверки.
  • Отсутствие записи о занятости означает, что каталог не отмечает дату как занятую; фактическую доступность нужно подтвердить у подрядчика.
  • price_from_kzt — цена «от». Итоговую стоимость требуется уточнить у подрядчика.
  • Сервис не бронирует услуги и не отправляет заявки.

Подробная схема модулей и API: ARCHITECTURE.md.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
1
Авторы
1
Файлы
37
Ветки
1

Авторы коммитов

alimzanovolzas14-ops 1

История коммитов

  • 2026-09-23 17:31Add files via uploadalimzanovolzas14-ops
Структура репозитория (37 файлов)
ARCHITECTURE.md
README.md
api.env
app.py
data.csv
docs/superpowers/plans/2026-09-23-event-match-web-implementation.md
docs/superpowers/plans/2026-09-23-personal-contractors-and-ai.md
docs/superpowers/specs/2026-09-23-event-match-web-design.md
docs/superpowers/specs/2026-09-23-personal-contractors-and-ai-design.md
event_matcher/__init__.py
event_matcher/api/__init__.py
event_matcher/api/application.py
event_matcher/api/routes.py
event_matcher/api/schemas.py
event_matcher/config.py
event_matcher/data.py
event_matcher/repositories/__init__.py
event_matcher/repositories/catalog.py
event_matcher/repositories/supabase.py
event_matcher/services/__init__.py
event_matcher/services/ai_analysis.py
event_matcher/services/catalog.py
event_matcher/services/explanations.py
event_matcher/services/matching.py
event_matcher/services/providers.py
event_matcher/services/relevance.py
requirements.txt
static/css/styles.css
static/index.html
static/js/ai.js
static/js/app.js
static/js/auth.js
static/js/providers.js
supabase/migrations/202609230001_personal_contractors.sql
tests/test_api.py
tests/test_catalog.py
tests/test_matching.py

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.