Firebird
Статический сайт на GitHub Pages для подбора до трёх event-подрядчиков с цитатами из профиля.
О проекте
Команда: RAM Network
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Статический сайт на GitHub Pages для подбора до трёх event-подрядчиков с цитатами из профиля. Есть избранное, сравнение, отзывы, интерфейс на ru/kk/en и локальный rule-based помощник. Отдельный Flask-сервер обслуживает аккаунты и заявки.
Как устроено
matcher.js фильтрует 66 профилей по городу, дате (исключает занятых), категории, бюджету и формату, а в каждую карточку добавляет фрагмент описания. assistant-local.js работает в браузере по правилам, без нейросети: сравнивает подборку, ищет минимальную цену при прочих ограничениях и применяет параметры только по кнопке. server.py (Flask, SQLite) даёт регистрацию, гостевые заявки с подтверждением по email и CAPTCHA. Справочник расширен до 20 городов с проверкой test_cities (1224 + 306 сценариев).
Ключевые решения
- rule-based подбор
- rule-based локальный ассистент
- исключение занятых по календарю
- i18n ru/kk/en
Особенности
Весь подбор и помощник работают в браузере без серверных вызовов и API-ключей, поэтому сайт размещён на GitHub Pages. Большое внимание UX: Bento-сетка, мобильная навигация, поддержка prefers-reduced-motion. Демо-отзывы явно помечены как вымышленные и на подбор не влияют.
Стек
JavaScript · HTML/CSS · Python · Flask · SQLite · Node test runner · GitHub Pages · Docker
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-6cfe7a0f-ram-network.
README
README.mdFirebird — умный подбор подрядчиков (#79-lite)
Сервис помогает заказчику выбрать до трёх event-подрядчиков из предоставленного каталога. Каждая карточка объясняет совпадение с запросом и приводит конкретный фрагмент описания профиля. Занятые на дату подрядчики не попадают в выдачу.
Открыть сайт: https://imfrqte.github.io/Rampage/index.html
Репозиторий команды: https://github.com/imfrqte/Rampage
Русский, қазақша, English и ИИ-помощник
Переключатель языка находится в шапке. Он переводит интерфейс, формы, карточки, сравнение, личный кабинет и сообщения, сохраняя введённые параметры. Выбор запоминается в браузере; доступны ссылки ?lang=ru, ?lang=kk, ?lang=en. Имена и исходные тексты описаний/отзывов сохраняются на языке источника.
Кнопка «Помощник» открывает локального помощника без сервера, регистрации и API-ключей. После загрузки страницы вопросы обрабатываются в браузере, без сетевых запросов. Он сравнивает текущую подборку, ищет минимальную начальную цену с сохранением остальных ограничений, предлагает план подготовки и разбирает поддерживаемые запросы о городе, дате, категории и бюджете. Изменения формы применяются только по кнопке «Применить параметры».
Это подбор по правилам (assistant-local.js), не нейросеть и не универсальный чат. Неоднозначные или неподдерживаемые запросы требуют уточнения; цены и доступность берутся из демонстрационного каталога с календарём 23.09–31.12.2026. История диалога хранится только в памяти страницы и исчезает при обновлении. Для первой загрузки опубликованного сайта нужен интернет; офлайн-кеш всего сайта не устанавливается. Тесты: node --test assistant-local.test.cjs.
Прежняя облачная интеграция сохранена в папке assistant/ для отдельного будущего подключения, но текущий интерфейс её не вызывает и ai-config.json не читает. Новая локальная реализация помощника не меняет авторизацию: общие аккаунты и письма по-прежнему требуют настроенного backend.
Аккаунты, заявки и письма
Без обязательной регистрации
Подбор, избранное, сравнение и просмотр профилей доступны сразу. На статическом GitHub Pages можно создавать, редактировать, отменять и удалять демо-заявки без почты и пароля. Они сохраняются только в этом браузере, не отправляются подрядчикам и не превращаются автоматически в настоящие заявки. При недоступном хранилище интерфейс предупреждает, что данные останутся только до перезагрузки. Вход и регистрация сохранены; в формах входа и регистрации есть «Продолжить без входа».
На настроенном Python-сервере доступна настоящая заявка без аккаунта: имя, email, дата, бюджет и пожелания. Ссылка из письма подтверждает адрес, после чего запрос поступает оператору. Пароль и регистрация не требуются. Статусы и отмена доступны из браузера, связанного с заявкой. Общая база, доставка писем и проверка CAPTCHA требуют развёртывания по SERVER.md; GitHub Pages сам эти службы не запускает. Гостевые запросы не создают записи зарегистрированных пользователей и не подключают рассылку автоматически.
guest-store.js хранит только локальные демо-заявки. node --test guest-store.test.cjs проверяет календарь, бюджет, сохранение, редактирование, отмену, удаление и работу при недоступном хранилище. Серверный гостевой сценарий проверяет python -m unittest test_guest_server без настоящей отправки писем.
В текущий Bento-интерфейс добавлены вход и регистрация, подтверждение почты, восстановление пароля, личный кабинет, подписка на новых подрядчиков и заявки с датой, примерным бюджетом и пожеланиями. В карточках и профилях кнопка называется «Демо-заявка» на GitHub Pages и «Оставить заявку» на настроенном сервере. Статусы и отмена находятся в соответствующем списке заявок; гостевой список доступен и после входа в аккаунт.
Кнопка «Продолжить без входа» возвращает к подбору с сохранением параметров или продолжает гостевую заявку на уже выбранного подрядчика. Личный кабинет требует входа; гостевые заявки доступны отдельно, без пароля. Настоящую заявку нужно подтвердить по почте.
На GitHub Pages сервер не работает: каталог, отзывы в браузере и избранное доступны, но настоящая регистрация, сохранение общих заявок, CAPTCHA и отправка писем требуют отдельного запуска сервера. До подключения формы явно показывают этот статус и не создают фиктивные аккаунты.
Серверная часть — server.py (Flask/SQLite), интерфейс — accounts.js и accounts.css. Настройка, локальный режим без реальных писем, обработка заявок и запуск рабочего почтового процесса описаны в SERVER.md. Секретные ключи и базу данных нельзя добавлять в GitHub. test_server.py проверяет API и ограничения доступа.
Заявка — запрос на согласование, а не оплата или гарантированная бронь. Каталог демонстрационный; реальные контакты подрядчиков не предоставлены, поэтому заявки не рассылаются им автоматически. Подписка добровольная и работает только после подтверждения почты.
Города Казахстана
В выборе города доступны Алматы, Астана, Шымкент, Караганда, Актобе, Тараз, Павлодар, Усть-Каменогорск, Семей, Атырау, Костанай, Кызылорда, Уральск, Петропавловск, Кокшетау, Туркестан, Талдыкорган, Актау, Жезказган, Конаев и «Зарубежье».
Это расширение справочника, а не количества подрядчиков: все 66 исходных профилей сохранены. Пока в новом городе нет профилей выбранной категории, сайт показывает «В этом городе такой категории нет» и предлагает изменить город или категорию. Проверка: node test_cities.cjs (1224 прежних сценария и 306 запросов новых городов).
Быстрый запуск
Каталог разделён на HTML, CSS и JavaScript. Все рабочие файлы находятся непосредственно в корне репозитория. index.html — главная страница, Firebird.html — такая же страница для совместимости со старыми ссылками. Для статического каталога API-ключи, сборка и установка пакетов не нужны. Для аккаунтов, заявок и почты используйте серверный запуск из SERVER.md, а не простой HTTP-сервер ниже.
Скачайте репозиторий и запустите из его корня локальный HTTP-сервер (нужен Python 3):
python -m http.server 4173 --bind 127.0.0.1
Откройте http://127.0.0.1:4173.
Совместное редактирование
Участники с правом записи в репозиторий могут редактировать файлы через GitHub или локально. Для одновременной работы используйте отдельные ветки и pull request в main. После сохранения изменений в main GitHub Pages публикует обновлённый сайт. Наличие имени в списке Contributors само по себе не предоставляет право записи.
При изменении разметки обновляйте index.html и Firebird.html одинаково. При изменении CSS или JavaScript обновляйте параметр ?v= соответствующего ресурса в обеих HTML-страницах, чтобы сбросить браузерный кеш.
Старые архивы, отдельная прежняя серверная версия, автономная копия и дублирующая документация убраны; их можно восстановить через историю Git. Новый server.py обслуживает текущий сайт, а не отдельный HTML-дубликат. Версия до очистки также содержит исходный CSV, прежний сборщик и тесты подбора внутри архива проекта.
Улучшения интерфейса и UX
- Bento Grid: асимметричная сетка первого экрана, лавандовые и лаймовые плитки, крупная первая рекомендация и две компактные карточки на широком экране.
- Живая мини-подборка на первом экране, переход в профиль одним нажатием, быстрые сценарии и календарь с переключением дня в пределах известного периода.
- Плавное появление плиток, переходы вкладок, эффекты наведения, лёгкий наклон плиток под мышью, индикатор прокрутки и декоративные орбиты на Canvas.
- Кнопка «Анимации» сохраняет предпочтение в браузере. Системное
prefers-reduced-motionотключает движение; Canvas останавливается вне экрана и в скрытой вкладке. Сами результаты не зависят от анимаций. - Отдельная вкладка «Избранные подрядчики» с карточками, переходом в профиль и сравнением; управление вкладками мышью и клавишами со стрелками.
- У каждого подрядчика и автора отзыва — стабильная иллюстративная SVG-аватарка, без внешних сервисов и реальных фотографий.
- В профиле — отзывы с именем, фамилией, датой, текстом и оценкой 1–5 звёзд. Встроенные отзывы и рейтинг явно помечены как демонстрационные: они вымышлены, не относятся к исходному датасету и не влияют на подбор.
- Форма своего отзыва с проверкой имени, фамилии, оценки и длины текста. Дата проставляется автоматически. До 20 локальных отзывов на профиль хранятся только в текущем браузере (
firebird:reviews:v1); их можно удалить. Это не серверная публикация, другим посетителям они не видны. Собственные отзывы показаны отдельно от демо-рейтинга. - Избранное: до трёх профилей, сохранение в текущем браузере и таблица сравнения цены, языков, форматов и длительности.
- Сравнение повторно проверяет условия последнего выполненного запроса, включая занятость на дату. Сохранённый профиль не считается автоматически доступным.
- Восстановление последнего успешного подбора после перезагрузки. Кнопка «Сбросить» возвращает исходные параметры, сохраняя избранное.
- На телефоне — нижняя навигация к параметрам, результатам и избранному, переход к результатам после поиска и зоны нажатия от 44 px.
- Улучшенные карточки, акцентная кнопка начала подбора, уведомления, ссылка пропуска навигации, клавиатурный фокус и поддержка уменьшения анимации.
- Предпочтения хранятся локально под ключом
firebird:preferences:v1, не отправляются на сервер. При недоступном хранилище подбор и избранное работают в пределах открытой страницы.
styles.css и app.js задают основной интерфейс, ux.css и ux.js — избранное и сохранение параметров, community.css, community-data.js, community.js — отзывы и иллюстративные аватарки, bento.css и bento.js — Bento-композицию и интерактивные эффекты. Эти файлы находятся рядом с HTML и загружаются браузером напрямую. Редактируйте их в корне репозитория.
Что реализовано
- Все 66 профилей, 17 категорий, 6 форматов из датасета; справочник расширен до 20 городов Казахстана и «Зарубежья».
- Обязательные входы: город, дата, формат, категория, бюджет в тенге за мероприятие. Опциональные: язык и длительность присутствия.
- До трёх карточек с именем, категорией, городом, ценой «от» и объяснением на основании полей и дословного фрагмента описания.
- Три явных исхода:
matched— подобрали;no_category— в городе нет этой категории;no_matches— категория есть, но никто не прошёл все условия. - Если карточек меньше трёх, указано количество исходных кандидатов и причины исключения. У профиля может быть несколько причин; их счётчики не нужно складывать.
- Площадки и люди проходят один и тот же фильтр занятости. Поиск по любой категории из списка профиля поддерживается.
- После смены только даты показано, кто из прежней подборки теперь занят и кто из новой был занят раньше.
- Цены и города, заполненные при подготовке датасета, отмечены отдельно. Синтетические профили организаторов отличимы от остальных анонимизированных профилей.
- Пять кнопок демонстрационных запросов, подробный профиль с источником, адаптивная форма и необязательный WebMCP-инструмент для поддерживающих браузеров.
Как устроено решение
- Валидация. Проверяем значения справочников, дату, бюджет, язык и длительность. Календарь известен только с 23.09.2026 по 31.12.2026 включительно; вне этого окна выдаём понятную ошибку, не предполагаем свободные даты.
- Город и категория. Сначала формируем исходный список. Пустой список означает отдельный исход
no_category, независимо от других фильтров. - Жёсткие фильтры. Исключаем занятых (
busy_dates), неподдерживаемый формат, начальную цену выше бюджета, неподдерживаемый язык, недостаточныйmax_hours. Пустая начальная цена не принимается за ноль.max_hours = nullозначает работу без привязки к присутствию, поэтому фильтр длительности не применяется. - Детерминированное ранжирование. Считаем число различных тематических основ слов в описании для выбранного формата. Например, для корпоратива:
корпоратив,бизнес,делов,бренд,компан,тимбил. При равенстве сначала идут записи безprice_imputed, затем безcity_imputed, затем с меньшей начальной ценой и меньшим лексикографическим ID.syntheticне влияет на порядок. - Объяснение. В карточке отдельно показаны совпадения по полям, статус календаря и дословный фрагмент описания. В подробном профиле доступно полное текстовое объяснение. Выбор фрагмента учитывает формат, слова об услуге и редкость слов в корпусе; приветствия и перечисления клиентов штрафуются. Это извлечение текста, не генерация новых фактов. Полный исходный текст и ID доступны в карточке.
- Выдача. Берём первые три записи. Объясняем недостаток вариантов и сохраняем проверяемые причины исключения остальных.
Одинаковый запрос возвращает одинаковые ID, порядок и объяснения. Время, случайные числа и сетевые ответы не участвуют в расчёте. Числовой балл — прозрачная эвристика, не вероятность качества подрядчика.
Архитектура и технологии
Подбор и локальный помощник работают в статических HTML/CSS/JavaScript без библиотек, API-ключей и сервера приложений. Аккаунты, общие заявки и письма используют отдельную серверную часть на Python. assistant.js — интерфейс чата, assistant-local.js — локальный разбор запросов с использованием того же matcher.js; форма не меняется без нажатия кнопки применения. Обученная модель, эмбеддинги и дообучение в текущем браузерном режиме не используются.
catalog.js → данные каталога в браузере
Форма → matcher.validate → фильтры → ранжирование → объяснения → app.js → карточки
index.html,Firebird.html,styles.css— основные страницы и оформление.catalog.js— типизированные поля исходного CSV и происхождение данных (включая SHA-256).matcher.js— фильтрация, ранжирование, объяснения и сравнение дат.app.js— форма, карточки, состояния, примеры, диалог профиля и WebMCP.- Остальные CSS/JS расширяют интерфейс, как описано выше.
Данные и смысл цены
Источник — предоставленный участником hackathon dataset anonymized .csv; для текущего сайта данные включены в catalog.js. Исходный CSV сохранён без изменения байтов в прежнем архиве проекта, доступном через историю Git. HTML-превью использовалось только как справочный материал; основным источником служит CSV. JSONL не предоставлялся.
В датасете 66 записей: 53 анонимизированных несинтетических профиля и 13 синтетических профилей организаторов. Город заполнен при подготовке в 8 записях, цена — в 18. Собственные синтетические профили не добавлены. Имена вымышленные. У одного подрядчика может быть несколько категорий, поэтому сумма численности категорий превышает 66.
price_from_kzt — цена от за мероприятие, не фиксированная смета и не почасовая ставка. Проверка price_from_kzt <= budget означает только прохождение фильтра начальной цены. Не обещаем экономию, фиксированный пакет или окончательную стоимость. Цена не умножается на часы.
busy_dates полностью определяет календарь в указанном 100-дневном окне. Отсутствие даты в списке означает «не занят по календарю датасета», а не подтверждение от реального подрядчика.
Демонстрация для жюри
Откройте «Попробовать готовый сценарий» над результатами и выберите пример или заполните форму вручную. Язык и длительность находятся в блоке «Дополнительные пожелания».
| Сценарий | Параметры | Ожидаемый результат |
|---|---|---|
| Плотная категория | Алматы, 06.10.2026, корпоратив, Ведущий, 1 500 000 ₸, любой язык, без длительности | 7 прошедших фильтры; показаны Куррапика (HK-88430), Буллма (HK-44733), Джинбей (HK-75012) |
| Другая дата | Тот же запрос, 07.10.2026 | Буллма занят; в тройке вместо него Кики (HK-35215); показана причина изменения |
| Редкая категория | Алматы, 04.10.2026, свадьба, Флорист, 500 000 ₸, 8 ч | Тихиро Огино (HK-90001) и Тони Тони Чоппер (HK-39372); всего 2 флориста в городе, лимит часов не применяется |
| Без совпадений | Алматы, 26.12.2026, корпоратив, Ведущий, 100 000 ₸ | Категория существует, но кандидаты не проходят ограничения; видны причины |
| Категория отсутствует | Астана, 14.11.2026, свадьба, Декоратор, 3 000 000 ₸ | Отдельное сообщение: в городе такой категории нет |
| Площадка | Алматы, 14.11.2026, свадьба, Банкетный зал, 6 000 000 ₸, 6 ч | Гохан (HK-90011) и Иноскэ Хашибира (HK-64395), занятые площадки исключены |
Повторите первый запрос: порядок и тексты сохранятся. Откройте «Смотреть профиль», чтобы сверить объяснение с исходным описанием, языком, длительностью и флагами.
Проверки
До очистки для текущей логики были выполнены тесты трёх исходов, календарных границ, цены на границе бюджета, языка, часов и null, занятости площадок, повторяемости, независимости от порядка строк и извлечения фрагментов строго из источника. Также проверены 1 224 сочетания города, категории, формата и даты независимым фильтром и занятая дата каждого из 66 профилей. Тестовые скрипты доступны в прежнем архиве через историю Git; в минимальную текущую публикацию они не входят.
Ограничения и развитие
Нет оплаты и независимой проверки сведений у подрядчиков. Заявки и почтовые уведомления требуют настроенного сервера; подтверждение заявки оператором не заменяет договорённость с реальным подрядчиком. Поиск работает только по предоставленному каталогу и календарю. Свободный текст не переопределяет структурированные город, формат, язык, цену или занятость. Лексическая эвристика может пропускать синонимы и не понимает отрицания как полноценная языковая модель.
Следующий шаг — сравнить текущий метод с готовыми эмбеддингами на оценённых запросах, сохранив жёсткие фильтры и проверяемые объяснения. API-ключи при такой интеграции должны храниться на сервере. Автоматическая отправка решения на платформу хакатона не выполнялась.
Авторы коммитов
История коммитов
- 2026-09-23 17:42Add files via uploadimfrqte
- 2026-09-23 17:41Import complete Firebird website, guest requests and servernur940
- 2026-09-23 10:23Add lightweight page interactionsimfrqte
- 2026-09-23 10:23Create new RAM Network visual systemimfrqte
- 2026-09-23 10:23Redesign hackathon landing pageimfrqte
- 2026-09-23 10:10Configure GitHub Pages deploymentimfrqte
- 2026-09-23 10:10Add RAM Network landing pageimfrqte
- 2026-09-23 10:09Add RAM Network landing pageimfrqte
Структура репозитория (49 файлов)
.dockerignore .env.example .github/workflows/pages.yml .gitignore Dockerfile Firebird.html README.md Rampage-main (1).zip SERVER.md account-translations.js accounts.css accounts.js ai-config.json app.js assistant-local.js assistant-local.test.cjs assistant.css assistant.js assistant/.env.example assistant/Dockerfile assistant/README.md assistant/engine.mjs assistant/server.mjs assistant/tests.test.mjs bento.css bento.js catalog.js community-data.js community.css community.js demo-translations.js guest-store.js guest-store.test.cjs i18n.js index.html matcher.js requirements.txt script.js server.py style.css styles.css test_cities.cjs test_guest_server.py test_server.py theme.css theme.js translations.js ux.css ux.js
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.