AAYMA
RU
Войти

Firebird

Статический сайт на GitHub Pages для подбора до трёх event-подрядчиков с цитатами из профиля.

Рабочий MVP
Команда «RAM Network» 4💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: 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.md

Firebird — умный подбор подрядчиков (#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-инструмент для поддерживающих браузеров.

Как устроено решение

  1. Валидация. Проверяем значения справочников, дату, бюджет, язык и длительность. Календарь известен только с 23.09.2026 по 31.12.2026 включительно; вне этого окна выдаём понятную ошибку, не предполагаем свободные даты.
  2. Город и категория. Сначала формируем исходный список. Пустой список означает отдельный исход no_category, независимо от других фильтров.
  3. Жёсткие фильтры. Исключаем занятых (busy_dates), неподдерживаемый формат, начальную цену выше бюджета, неподдерживаемый язык, недостаточный max_hours. Пустая начальная цена не принимается за ноль. max_hours = null означает работу без привязки к присутствию, поэтому фильтр длительности не применяется.
  4. Детерминированное ранжирование. Считаем число различных тематических основ слов в описании для выбранного формата. Например, для корпоратива: корпоратив, бизнес, делов, бренд, компан, тимбил. При равенстве сначала идут записи без price_imputed, затем без city_imputed, затем с меньшей начальной ценой и меньшим лексикографическим ID. synthetic не влияет на порядок.
  5. Объяснение. В карточке отдельно показаны совпадения по полям, статус календаря и дословный фрагмент описания. В подробном профиле доступно полное текстовое объяснение. Выбор фрагмента учитывает формат, слова об услуге и редкость слов в корпусе; приветствия и перечисления клиентов штрафуются. Это извлечение текста, не генерация новых фактов. Полный исходный текст и ID доступны в карточке.
  6. Выдача. Берём первые три записи. Объясняем недостаток вариантов и сохраняем проверяемые причины исключения остальных.

Одинаковый запрос возвращает одинаковые 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-ключи при такой интеграции должны храниться на сервере. Автоматическая отправка решения на платформу хакатона не выполнялась.

Звёзды
⭐ 0
Форки
0
Язык
JavaScript
Последний push
в прошлом месяце
Коммиты
8
Авторы
2
Файлы
49
Ветки
4

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

imfrqte 8nur940 1

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

  • 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
Ветки (4)

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

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

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