EventMatch
Сервис подбора до 3 подрядчиков для мероприятия по анонимизированному каталогу (66 профилей) с объяснениями, календарём доступности, подбором…
О проекте
Команда: WESTcoder
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Сервис подбора до 3 подрядчиков для мероприятия по анонимизированному каталогу (66 профилей) с объяснениями, календарём доступности, подбором команды из 1–5 ролей и планом Б на соседние даты.
Как устроено
CSV/JSON каталог загружается в память, затем обязательные фильтры (город, категория, дата, формат, цена, длительность, язык) формируют воронку отсева. Ранжирование детерминированное: соответствие пожеланиям (вес 80, по ключевым словам или по сходству embeddings) плюс запас бюджета (вес 20). Команду подбирают динамическим программированием по подмножествам ролей, O(N×R×2^R), с минимальной суммой цен и уникальными исполнителями. Модуль relaxation пересчитывает варианты с изменёнными условиями. Опциональный OpenAI используется только для разбора свободного описания события.
Ключевые решения
- детерминированный скоринг с весами
- embeddings-сходство
- динамическое программирование по подмножествам ролей
- релаксация ограничений
- SQLite-кэш embeddings
- воронка фильтров
Особенности
Подбор команды из нескольких ролей через DP по подмножествам ролей с условием уникальности исполнителей, а не жадный выбор самого дешёвого на каждую роль. Для даты вне календаря каталога API возвращает 422, неизвестная цена не приравнивается к нулю. Экспортирует бриф мероприятия в .txt.
Стек
Python · стандартная библиотека http.server · HTML/CSS/JS · SQLite
Модели
OpenAI (опционально)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-949b5db0-westcoder.
README
README.mdEventMatch — умный подбор event-подрядчиков
MVP команды WESTcoder для HackAlem. Подбор подрядчиков и команды для мероприятия по анонимизированному каталогу хакатона.
Команда: Nurtilek Koblandy, Meirbek Arystanov, Nurkeldi Adilov.
Запуск
Нужен Python 3.11+. Backend использует стандартную библиотеку, установка пакетов не требуется.
Из корня репозитория:
python -m backend.server
Откройте http://127.0.0.1:8000. Остановка — Ctrl+C. Другой порт: python -m backend.server --port 8080.
Backend и frontend обслуживаются одним процессом. Сборка frontend не нужна. При изменениях Python перезапустите сервер; при изменениях HTML/CSS/JS обновите страницу.
После git pull также перезапустите уже работающий сервер. Если новые блоки появились без оформления или кнопки не работают, проверьте /studio.css и /planner.js: ответ 404 при наличии файлов означает, что старый процесс ещё использует прежний список маршрутов. Остановите его через Ctrl+C, запустите python -m backend.server --port 8765 (либо ваш порт) и обновите страницу через Ctrl+F5.
Рабочий интерфейс — frontend/index.html, его обслуживает Python-сервер. Открытие HTML напрямую или через обычный Live Server не запускает API. Корневой index.html содержит инструкцию запуска; about.html описывает проект. Untitled-1.html — статический предпросмотр каталога.
В VS Code выберите Run and Debug → EventMatch: Python server → F5. Также доступны задачи EventMatch: Run и EventMatch: Tests. Служебные папки .tools и .venv исключены из поиска и анализа. C/C++-исходники внутри этих папок открываются как текст: это код установленных зависимостей, а приложение использует готовые бинарные модули. Диагностика кода проекта остаётся включённой. Если вкладки зависимостей были открыты до изменения настроек, выполните Developer: Reload Window. Настройка основана на ассоциациях файлов VS Code и исключениях C/C++.
Расширение C/C++ Runner для этого Python-проекта не требуется: оно автоматически восстанавливает свои конфигурации при удалении. Если оно уже активно, выберите для него Disable (Workspace) и выполните Developer: Reload Window. Его автоматически созданный вариант запуска скрыт из списка; для приложения используется EventMatch: Python server. В конфигурации IntelliSense убрана ссылка на отсутствующий GCC и указан существующий каталог заголовков установленного Python (C:/Python314/Include на этом компьютере). На другой машине путь можно получить командой python -c "import sysconfig; print(sysconfig.get_path('include'))". Компиляция исходников зависимостей для запуска приложения не требуется.
Возможности
- EventMatch Studio: адаптивный интерфейс с последовательностью «идея → подрядчики → команда → следующий шаг».
- Описание события своими словами: редактируемый черновик, опциональный OpenAI и явно обозначенный локальный разбор без ключа.
- До трёх подрядчиков по городу, дате, категории, формату, бюджету, часам работы и языку.
- Пожелания к стилю: «спокойная подача, без конкурсов» или «живая музыка, джаз».
- Сортировка по пожеланиям либо по стартовой цене.
- Объяснения, цитаты, неподтверждённые пожелания и возможные противоречия.
- Календарь числа подходящих профилей на каждый из 100 дней. Нажатие на дату запускает подбор. Изменение формы помечает старый календарь неактуальным.
- Избранное в localStorage, сравнение двух–четырёх профилей, повторная проверка сохранённого запроса. При недоступном хранилище список работает до закрытия страницы.
- Проверяемые подсказки с изменением от одного до трёх условий, применяемые только по нажатию.
- Команда из одной–пяти ролей: общая дата и бюджет, отдельные часы для каждой роли, разные подрядчики. При нехватке бюджета показывается минимальная сумма полной команды, если она существует.
- План Б: до трёх полных команд на соседние даты в пределах ±7 дней. Резерв 0–30% вычитается из общего бюджета до подбора. При выборе варианта бюджет команды уменьшается на резерв; повторно он не вычитается.
- Бриф мероприятия в UTF-8
.txt: условия, состав команды, стартовые цены и вопросы подрядчикам. Изменение условий скрывает экспорт устаревшего подбора.
Сценарий для жюри, анализ аналогов и следующие продуктовые шаги: PRODUCT_PLAN.md. Проверка требований кейса #79-lite, критерии на 100 баллов и оставшиеся риски: HACKATHON_CHECKLIST.md.
Архитектура
CSV / JSON / JSONL
→ dataset.py: загрузка и нормализация в памяти
→ models.py: проверка запроса и правил датасета
→ filters.py: обязательные ограничения и воронка
→ preferences.py / semantic.py: локальная проверка пожеланий или embeddings описаний
→ scoring.py: детерминированная оценка
→ service.py: сортировка по баллу или цене, максимум 3; календарь
→ team.py: команда с минимальной общей ценой и уникальными исполнителями
→ explanations.py: объяснения из фактов
→ relaxation.py: пересчёт альтернативных условий
→ server.py: REST API
→ frontend/: HTML, CSS, JavaScript
Все ограничения и числовые оценки считаются локально. Для 66 записей достаточно последовательного прохода; отдельные БД каталога и векторное хранилище не требуются. SQLite используется только для опционального кэша embeddings.
Алгоритмы
Фильтры: город → категория → доступность → формат → цена → длительность → язык. Сравнение строк без учёта регистра и лишних пробелов. Бюджет и часы проверяются включительно.
Обязательные условия проверяются до ранжирования. Пожелания не могут вернуть занятого или неподходящего по бюджету подрядчика.
В режиме пожеланий балл состоит из соответствия описанию (вес 80) и запаса бюджета (20). Без анализа описания учитывается только запас бюджета. В режиме цены порядок определяется стартовой ценой. В режиме пожеланий сортировка — score DESC → id ASC; в режиме цены — price_from_kzt ASC → id ASC. Балл не является вероятностью или рейтингом качества.
| Фактор | Вес | Балл 0–100 |
|---|---|---|
| Запас бюджета | 20 | 100 × (1 − price_from_kzt / budget_kzt) |
| Соответствие описанию | 80 | Локальная проверка пожеланий или сходство embeddings |
Итог — сумма балл × вес, делённая на сумму активных весов, с округлением до двух знаков. При нулевых бюджете и цене бюджетный компонент равен 100. Если анализ описания недоступен, его вес исключается. Формат, язык и длительность проверяются обязательными фильтрами.
В деталях карточки видны компоненты оценки, веса и факты из профиля. Объяснения рекомендаций строятся локально. Опциональная генеративная модель применяется только для разбора черновика события. Воронка считает каждый профиль на первом непройденном условии; подробный список показывает все нарушения. Прошедшие фильтры кандидаты ниже топ-3 указаны отдельно.
Без внешнего API используется проверка ключевых слов, небольшого словаря близких выражений и простых отрицаний. Это не полноценное понимание произвольного текста. Отсутствие слова не доказывает отсутствие услуги; такие пожелания помечаются как неподтверждённые.
При включённых embeddings ранжирование использует смысловое сходство запроса и описания. Цитаты и отметки противоречий остаются результатом локальной проверки слов, а не объяснением каждого значения embeddings.
Для команды выбирается минимальная сумма стартовых цен. Динамическое программирование по наборам ролей проверяет уникальность исполнителей, а не выбирает по одному самому дешёвому независимо. Сложность: O(N × R × 2^R), где R ≤ 5. Один профиль не может выполнять две роли одновременно.
Фактический датасет
data/contractors.csv — побайтовая копия пользовательского файла hackathon dataset anonymized .csv. Исходный файл не изменялся, новые профили не добавлялись. Имеющийся Untitled-1.html сохранён.
SHA-256: 6a724b6b7dfb5973343e68ba18dadb60fc807d87e3d78f03ee86fb26cb089f7d.
| Поле | CSV → приложение |
|---|---|
id, anon_name | Строковые ID и анонимное имя |
categories | Список категорий, разделитель | |
city | Алматы, Астана, Зарубежье |
price_from_kzt | Начальная цена за мероприятие; пустая/невалидная → неизвестна |
event_formats, languages | Списки, разделитель | |
max_hours | Максимум часов; пустая строка → None |
busy_dates | Занятые даты ISO, разделитель | |
description | Исходное описание |
synthetic, city_imputed, price_imputed | Флаги True/False |
66 профилей, 17 категорий: Алматы — 50, Астана — 15, Зарубежье — 1. Синтетических профилей — 13; город проставлен у 8, цена у 18; пустой max_hours у 9. Цены: 100 000–6 000 000 ₸. Подробнее: анализ датасета.
Правила исходного каталога:
- Календарь: 2026-09-23 — 2026-12-31. Вне окна API возвращает 422: отсутствие записи не подтверждает доступность за пределами известного календаря.
- Для
Флорист,Декоратор,Подарки и сувенирыпустойmax_hoursозначает работу без почасового присутствия и не препятствует подбору с длительностью. - Некорректный
max_hours(-1, boolean, нечисловая строка) или отсутствующее поле не равны явно заданномуnull: при требовании часов профиль исключается с причинойduration_invalid. - Для остальных категорий неизвестный лимит не подтверждает запрошенную длительность и приводит к исключению. Без требования часов фильтр не применяется.
- Пустой список занятых дат — отсутствие занятости в пределах окна. Отсутствующий,
nullили повреждённый календарь — неизвестная доступность, кандидат исключается. - Разделители без дат (
|,||), пустые элементы между датами и даты с завершающим|считаются повреждённым календарём. Явно пустая строка CSV и пустой массив остаются допустимыми. - Неизвестная цена не считается нулевой. Синтетические и проставленные значения помечены в интерфейсе.
Загрузчик поддерживает JSON (массив объектов) и JSONL. ID должны быть непустыми и уникальными. При замене DATASET_PATH нужно пересмотреть правила календаря и значение null, настроенные на исходный датасет.
HTML-preview содержит те же профили, что и исходный CSV.
- Цена «от» не является окончательной стоимостью. Сумма команды — ориентир без дополнительных услуг, логистики и доплат.
- Отсутствие даты в
busy_datesозначает отсутствие записи о занятости. Доступность нужно подтвердить; подбор не является бронированием. - Контакты, подтверждённые отзывы, фотографии портфолио и полная вместимость площадок не представлены и не выдумываются.
- Избранное хранит снимок профиля и параметров запроса в конкретном браузере. После изменения каталога или условий используйте «Перепроверить подбор».
Настройки
Опциональный семантический путь использует OpenAI Embeddings API. Для внешнего анализа скопируйте .env.example в .env, задайте свой OPENAI_API_KEY и ENABLE_EMBEDDINGS=true. Не добавляйте .env в Git. Без этих настроек всё работает локально.
| Переменная | По умолчанию | Назначение |
|---|---|---|
HOST | 127.0.0.1 | Адрес сервера |
PORT | 8000 | Порт |
ENABLE_EMBEDDINGS | false | Внешний анализ |
OPENAI_API_KEY | пусто | Ключ внешнего API |
EMBEDDING_MODEL | text-embedding-3-small | Модель embeddings |
ENABLE_AI_BRIEF | false | Разбор описания события через OpenAI Responses API |
BRIEF_MODEL | gpt-4.1-mini | Модель для структурированного черновика |
DATASET_PATH | data/contractors.csv | CSV, JSON или JSONL |
CACHE_DIR | .cache | Кеш SQLite |
Векторы кэшируются по модели и тексту. Ключ решения включает версию схемы, модель, SHA-256 датасета, точные параметры запроса и ID прошедших кандидатов. Близкие дробные бюджеты не смешиваются. Повреждённые векторы не используются. Обычный повтор сохраняет предыдущий результат, включая подбор без семантики после сбоя. Кнопка «Повторить AI-анализ» отправляет refresh_semantic: true и разрешает заменить неудачное решение после восстановления API; успешный ответ затем сохраняется. Это отдельное действие пользователя, которое может изменить порядок. Успешный кэш повторно к API не обращается. Новый CACHE_DIR для восстановления после обычной сетевой ошибки не нужен.
Разные запросы не блокируют друг друга во время сетевого вызова. Для одинакового запроса используется отдельная блокировка, чтобы не выполнять дублирующие вызовы. SQLite-соединения закрываются до обращения к API; запись результатов выполняется короткой транзакцией. Изменение конфигурации, данных, алгоритма или явный повтор AI-анализа может изменить оценку; обычные повторы при неизменном состоянии воспроизводимы.
Сетевой таймаут — 6 секунд. При недоступности API, отсутствии ключа или ошибке кеша используется локальная проверка пожеланий; если пожеланий нет, остаётся бюджетный компонент. UI показывает фактический режим. При неизменных данных, настройках и кеше порядок воспроизводим. Реальный внешний провайдер без пользовательского ключа не проверяется; тесты используют подмену транспорта.
API
Включение AI-разбора
Создайте .env по .env.example, если файла ещё нет. Не перезаписывайте существующий файл с ключами. В своём локальном .env установите:
OPENAI_API_KEY=ваш_ключ
ENABLE_AI_BRIEF=true
BRIEF_MODEL=gpt-4.1-mini
Перезапустите python -m backend.server. В блоке описания появится «AI-разбор · OpenAI». Если виден локальный режим, проверьте флаг и наличие ключа на сервере. При ошибке провайдера черновик явно сообщает о переходе к локальным правилам. Наличие настроек не доказывает работоспособность ключа: проверьте один реальный черновик после настройки аккаунта.
AI-разбор и embeddings включаются независимо. API-ключ не нужно добавлять в HTML, JavaScript, чат или Git. Реальные запросы могут тарифицироваться аккаунтом OpenAI.
backend/brief.py отправляет текст описания в Responses API с Structured Outputs. Ответ дополнительно проверяется: только значения справочников, даты известного календаря, конечные числа и до пяти уникальных ролей. Неизвестные поля остаются незаполненными. Пользователь проверяет черновик до применения. Модель не управляет ранжированием, не придумывает исполнителей и не подтверждает бронирование.
Запросы используют store: false, таймаут 12 секунд, лимит 900 выходных токенов и максимум 10 внешних вызовов в минуту на процесс. Отказ, таймаут, неполный или некорректный ответ возвращают локальный результат с уведомлением. Исходные ошибки провайдера и ключ не выводятся пользователю. Поддержка реального провайдера проверена заглушками транспорта; для живой проверки нужен ваш ключ.
Локальный разбор распознаёт явные города, роли, суммы в тенге и даты YYYY-MM-DD / DD.MM.YYYY. Сложные формулировки и неоднозначность нужно исправить в черновике. Это разбор по правилам, а не языковая модель.
Маршруты
| Метод | Путь | Результат |
|---|---|---|
| GET | /api/health | Состояние сервера |
| GET | /api/meta | Справочники, границы календаря и демо |
| POST | /api/recommend | Топ-3, объяснения, воронка, подсказки |
| POST | /api/calendar | Число кандидатов на каждый день |
| POST | /api/team | Полная команда или причина отсутствия решения |
| POST | /api/brief | { "text": "описание от 10 до 1500 символов" } → черновик, режим, незаполненные поля |
| POST | /api/plan | Запрос команды + reserve_percent (0–30, по умолчанию 10) → исходная дата и до трёх соседних вариантов |
Content-Type: application/json, максимум 16 KiB. Ошибки: 400 — некорректный или чрезмерно вложенный JSON; 413 — пустое или слишком большое тело; 415 — неправильный Content-Type; 422 — неверные поля. Отрицательные и бесконечные числа, boolean вместо числа и несуществующие даты отклоняются. Неизвестный город/категория даёт category_not_found; отсутствие подходящих профилей — no_candidates; успешный подбор — matched.
Запрос подбора или календаря:
{
"city": "Алматы",
"date": "2026-09-26",
"event_format": "свадьба",
"category": "Фотограф",
"budget_kzt": 600000,
"duration_hours": 6,
"language": "русский",
"preferences": "репортаж, естественные эмоции",
"sort_by": "style"
}
duration_hours и language могут быть null. preferences — до 1500 символов, по умолчанию пустая строка. sort_by — style или price.
Пример PowerShell:
$eventBody = @{
city = 'Алматы'
date = '2026-09-26'
event_format = 'свадьба'
category = 'Фотограф'
budget_kzt = 600000
duration_hours = 6
language = 'русский'
preferences = 'репортаж, естественные эмоции'
sort_by = 'style'
} | ConvertTo-Json
Invoke-RestMethod http://127.0.0.1:8000/api/recommend -Method Post -ContentType 'application/json; charset=utf-8' -Body ([System.Text.Encoding]::UTF8.GetBytes($eventBody))
Ответ содержит status, message, request, total_candidates (в городе и категории), eligible_candidates, recommendations, filter_stats, excluded_reasons, excluded_candidates, suggestions, semantic_mode, semantic_retry_allowed, dataset_sha256. В рекомендации — поля профиля, name, category, score, score_breakdown, reasons, warnings, explanation. Основная карточка показывает именно explanation из API. Опциональное поле запроса refresh_semantic принимает только boolean и разрешает повтор неудачного AI-анализа.
Запрос команды (budget_kzt — общий бюджет):
{
"city": "Алматы",
"date": "2026-09-26",
"event_format": "свадьба",
"budget_kzt": 2000000,
"language": "русский",
"roles": [
{"category": "Фотограф", "duration_hours": 6},
{"category": "Ведущий", "duration_hours": 4}
]
}
Подсказки возвращают объект changes, например {"budget_kzt":190000,"duration_hours":12}. Для изменения одного поля также сохранены field и value.
Демо для жюри
Кнопки над результатами выполняют запрос. Результаты ниже — без пожеланий и embeddings, исходный CSV. Для другого каталога демо строятся по его данным.
| Сценарий | Условия | Результат |
|---|---|---|
| Популярная категория | Алматы, 26.09.2026, свадьба, фотограф, 600 000 ₸, 6 ч, русский | 4 подходят; топ-3: Рок Ли, Сацуки Кусакабэ, Альфонс Элрик |
| Редкая категория | Алматы, 23.09.2026, свадьба, флорист, 600 000 ₸, 6 ч, русский | 2 подходят: Тони Тони Чоппер и Тихиро Огино |
| Никто не подходит | Первый запрос с бюджетом 50 000 ₸ | no_candidates, причины и подсказка по бюджету |
| Категории нет | Астана, декоратор, 26.09.2026 | category_not_found |
Поменяйте дату первого запроса на 27.09.2026: состав выдачи изменится. Откройте «Как мы выбрали?» и подробности карточки. Примените подсказку и сравните количество кандидатов. Каждая подсказка пересчитывается с изменением от одного до трёх параметров и предлагает только реальное увеличение числа совпадений.
Проверки
python -m unittest discover -v
node --check frontend/app.js
node --check frontend/features.js
node --check frontend/planner.js
Необязательный сквозной DOM-тест интерфейса (нужен Node.js 22+):
npm install jsdom --prefix .tools/ui-test --no-save --package-lock=false --ignore-scripts
node --test tests/frontend.test.mjs
Тест сам запускает локальный сервер на свободном порту. Он проверяет действия пользователя и сохранение состояния, но не заменяет визуальную проверку в браузере. Тестовая библиотека находится в игнорируемой папке .tools и не нужна приложению.
Тесты проверяют исходный CSV, весь календарь, обязательные ограничения, реальность подсказок, пожелания и отрицания, уникальность и оптимальность команды, границы бюджета, замену каталога, API и кеш. Внешний API в тестах заменён заглушкой.
Ручная проверка: сохранить два профиля, открыть сравнение, обновить страницу и проверить избранное; выбрать дату в календаре; применить составную подсказку; собрать команду и проверить нехватку общего бюджета.
Полный сценарий Studio в установленном Google Chrome, адаптивность на 360/390/768/1024/1440 px и автоматический аудит WCAG A/AA:
npm install playwright @axe-core/playwright jsdom --prefix .tools/ui-test --no-save --package-lock=false --ignore-scripts
node --test tests/browser.test.mjs
Этот тест сам запускает сервер на свободном порту. Он проверяет черновик и его редактирование, подбор команды, резерв, смену даты, скачивание файла, блокировку устаревшего экспорта и восстановление после ошибки. Скриншоты и отчёт доступности сохраняются в игнорируемой папке artifacts/. Автоматический аудит не заменяет ручную проверку всех состояний и вспомогательных технологий.
Чтобы проверить именно уже открытый локальный сервер, включая загрузку CSS/JS и применение оформления:
$env:EVENTMATCH_TEST_URL = 'http://127.0.0.1:8765'
try { node --test tests/browser.test.mjs }
finally { Remove-Item Env:EVENTMATCH_TEST_URL }
Для этого теста используйте локальный сервер с выключенными ENABLE_EMBEDDINGS и ENABLE_AI_BRIEF, чтобы проверки не обращались к платному API.
Браузерная проверка требует Playwright и установленный Google Chrome:
python -m pip install playwright
# В другом терминале должен работать python -m backend.server
python scripts/browser_smoke.py
Проверяет четыре демо, соответствие текста карточек объяснениям API, подсказки, дробные значения, восстановление сети, повторную загрузку каталога, кнопку повторного AI-анализа, отсутствие JS-ошибок, desktop 1440 px и mobile 390 px без горизонтального переполнения. Скриншоты: artifacts/ (не включаются в git).
Ограничения MVP
- Каталог статический, календарь заканчивается 31.12.2026. Отсутствие занятости не заменяет подтверждение подрядчиком.
- Цена «от» не является сметой. Оценка не учитывает качество работы и отзывы, которых нет в данных.
- Описания — заявления профиля, а не независимо проверенные факты. Синтетические записи помечены.
- Нет бронирований, сообщений, платежей, регистрации и редактирования каталога.
- Сервер стандартной библиотеки предназначен для локального демо. Для публичной эксплуатации нужны production-сервер, HTTPS и лимиты запросов.
Авторы коммитов
История коммитов
- 2026-09-23 17:46Fix duplicate planner script and verify frontend asset loadingMeiirbek Arystanov
- 2026-09-23 17:32Add EventMatch Studio planning workflow and hackathon documentationMeiirbek Arystanov
- 2026-09-23 16:27Update project filesMeiirbek Arystanov
- 2026-09-23 15:03Add about pageMeiirbek Arystanov
- 2026-09-23 17:39Update README.mdnureeek
- 2026-09-23 13:58Add initial HTML pageMeiirbek Arystanov
- 2026-09-23 16:58Merge latest README update from origin/mainNura007
- 2026-09-23 16:57Merge main: integrate event planning features and validation fixesNura007
Все коммиты (24)
- 2026-09-23 16:55Update README.mdnureeek
- 2026-09-23 13:54Update project statusMeiirbek Arystanov
- 2026-09-23 16:52Refactor contractor availability and duration validationNura007
- 2026-09-23 15:48Revise README for clarity and quick start sectionnureeek
- 2026-09-23 15:12Merge branch 'main' of https://github.com/BAITC-Hacks/hack-949b5db0-westcoderNura007
- 2026-09-23 15:12feat: enhance frontend validation and error handlingNura007
- 2026-09-23 14:53Merge branch 'main' of https://github.com/BAITC-Hacks/hack-949b5db0-westcoderNura007
- 2026-09-23 14:51first commitNura007
- 2026-09-23 14:50Revise Project Status and add folder structurenureeek
- 2026-09-23 14:49Merge branch 'main' of https://github.com/BAITC-Hacks/hack-949b5db0-westcoderNura007
- 2026-09-23 14:452md stepNura007
- 2026-09-23 14:00Update README with project planning detailsnureeek
- 2026-09-23 13:56starterNura007
- 2026-09-22 21:08Correct spelling of team member's namenureeek
- 2026-09-22 17:48Update README.mdNura
- 2026-09-22 17:47Update README with team members listNura
Структура репозитория (44 файлов)
.env.example .gitattributes .gitignore README.md Untitled-1.html about.html backend/__init__.py backend/brief.py backend/dataset.py backend/demos.py backend/embedding_cache.py backend/explanations.py backend/filters.py backend/models.py backend/planning.py backend/preferences.py backend/relaxation.py backend/scoring.py backend/semantic.py backend/server.py backend/service.py backend/team.py data/contractors.csv docs/HACKATHON_CHECKLIST.md docs/PRODUCT_PLAN.md docs/dataset-analysis.md frontend/app.js frontend/favicon.svg frontend/features.css frontend/features.js frontend/index.html frontend/planner.js frontend/studio.css frontend/styles.css index.html scripts/browser_smoke.py tests/__init__.py tests/browser.test.mjs tests/frontend.test.mjs tests/test_api.py tests/test_features.py tests/test_planning.py tests/test_recommendations.py tests/test_semantic.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.