EventMatch
AI-консультант по выбору event-подрядчиков: диалог (текстом или голосом) собирает условия мероприятия, Go-сервер строго фильтрует каталог и выдаёт…
О проекте
Команда: Soda
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
AI-консультант по выбору event-подрядчиков: диалог (текстом или голосом) собирает условия мероприятия, Go-сервер строго фильтрует каталог и выдаёт до трёх подрядчиков с фактами и цитатами, а при пустой выдаче показывает ближайшие альтернативы.
Как устроено
OpenAI Responses API со структурированным ответом извлекает из рассказа город, дату, формат, категорию, бюджет и пожелания, задавая по одному вопросу. Голос записывается MediaRecorder и расшифровывается через Transcriptions API. Go проверяет обязательные условия по каталогу и занятости в PostgreSQL. Прошедших сортирует смысловой индекс (эмбеддинги цитат и пожеланий), если он подготовлен, иначе по цене. Если совпадений нет, модуль alternatives показывает конкретные расхождения по цене, формату, дате и городу. В последней версии подключён Python-пайплайн (filters, ranker, generator).
Ключевые решения
- structured outputs
- strict constraint filtering
- embedding semantic ranking
- nearest alternatives
- occupancy calendar
- speech-to-text
Особенности
Размытые требования вроде «обязательно без конкурсов» не засчитываются молча: их нужно уточнить или явно согласиться продолжить без проверки. Бюджет, город и дату система сама не меняет. Демо закреплено на конкретном коммите ab45c2c.
Стек
Go · PostgreSQL · Python · JavaScript · HTML/CSS · Docker Compose
Модели
OpenAI Responses API · OpenAI Transcriptions API
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-d3e8cd85-soda.
README
README.md
AI-консультант для выбора event-подрядчиков из каталога.
Понимает идею события, уточняет детали и объясняет каждый вариант фактами.
Возможности · Скриншоты · Запустить · Архитектура · Проверить за 5 минут · Технический справочник
Go 1.25 PostgreSQL 17 OpenAI API JavaScript · HTML · CSS
Версия демонстрации: возможности, скриншоты и контрольные результаты ниже проверены на Go-версии
ab45c2c. Запуск закреплён на этом коммите. В актуальной версии подключён Python-поиск: он получает каталог из PostgreSQL, а Go дополняет ответ ближайшими вариантами и датами. Способы запуска и различия алгоритмов описаны в справочнике.
Хорошее событие начинается с подходящих людей
У заказчика уже есть каталог подрядчиков, но выбрать по нему непросто. Кто работает в нужном городе? Кто свободен? У кого подходящий формат? Почему один вариант лучше другого — и что делать, если никто не подошёл?
EventMatch превращает каталог в понятный выбор. Заказчик рассказывает о мероприятии обычными словами или голосом, вместе с AI уточняет условия и получает до трёх подрядчиков с конкретными объяснениями. Если совпадений нет, сервис показывает причины и ближайшие варианты для пересмотра условий.
Проект команды Soda для HackAlem AI, кейс Firebird «Умный подбор подрядчиков» (#79-lite). Основной пользователь — человек, который организует свадьбу, корпоратив, день рождения или другое событие и хочет разобраться в предложениях своего города.
| Понятный результат | Контроль у заказчика | Факты вместо общих похвал |
|---|---|---|
| До 3 подходящих карточек | Условия подтверждаются перед поиском | Проверенные поля и точные цитаты |
| Редкие категории и пустая выдача объясняются | Бюджет, город и дату не меняем молча | Занятые исключены из совпадений |
От «есть идея» до «вот подходящие варианты»
01 · Рассказать, а не заполнять всё с нуля
«Хочу оформить свадьбу, но не знаю, кто нужен» — достаточное начало разговора. AI помогает различить флориста и декоратора, задаёт по одному вопросу, предлагает короткие ответы и принимает свободный текст. Для фотографа уточняет стиль съёмки, для ведущего — характер подачи.
Рядом заполняется карточка «Мы поняли так». Уже известные условия передаются в следующий запрос вместе с историей и ручными исправлениями. Необязательное уточнение о стиле можно пропустить.
02 · Проверить, как нас поняли
Город, дата, формат, категория и бюджет в тенге обязательны. Язык и длительность — дополнительные ограничения. Все поля доступны для правки; диктовку тоже можно отредактировать до отправки.
Неоднозначные требования не исчезают: например, «обязательно без конкурсов» нельзя выдать за подтверждённую услугу только потому, что ведущий описан как спокойный. Такой пункт требует уточнения или явного согласия продолжить без его проверки.
03 · Выбрать дату с пониманием занятости
Интерактивный календарь показывает свободных кандидатов на каждый день и среднюю занятость по месяцам с учётом условий. Если выбранный подрядчик занят, сервис предлагает ближайшие даты без отметки о занятости в известном периоде.
04 · Сравнить конкретные причины
В выдаче — имя, категория, город, начальная цена и объяснение: факт из описания плюс соответствие условиям. Полный профиль раскрывает форматы, языки, часы работы и происхождение данных.
Если никто не подошёл, «Ближайшие варианты» показывают все различия: на сколько выше цена, какой формат не указан, другая ли это дата или город. Эти предложения отделены от строгих совпадений. Выбор новой даты возвращает к подтверждению, а не запускает бронирование.
Посмотрите, как это выглядит
Скриншоты работающей Go-версии ab45c2c. Каталог и результаты настоящие для предоставленного датасета; имена анонимизированы, синтетические профили отмечены в интерфейсе.
Первое знакомство

|
Диалог и живая карточка условий Один вопрос за раз. Ответ — кнопкой, текстом или голосом.
|
Календарь с занятостью Доступность по дням и нагрузка по месяцам из каталога.
|
Результат, который можно объяснить

Даже пустая выдача помогает сделать следующий шаг

И на телефоне — тот же понятный сценарий

Интерфейс проверен на ширинах 320, 768, 1024 и 1440 px. Есть управление с клавиатуры, подписи полей, озвучивание нового вопроса и поддержка системного уменьшения движения. Маленький персонаж-консультант, плавные появления и движение иллюстрации отключаются кнопкой паузы в шапке.
Запустить у себя
Нужны: Go 1.25+, Docker с Compose и Git. При первом запуске нужен интернет для загрузки зависимостей и образа PostgreSQL. Node.js, npm и сборка интерфейса не требуются.
git clone https://github.com/BAITC-Hacks/hack-d3e8cd85-soda.git
cd hack-d3e8cd85-soda
git checkout --detach ab45c2ca999be63447b47c055bf77d504759b4d6
docker compose up -d --wait db
go run .
Откройте localhost:8080. Команда go run . остаётся работать в терминале. Используйте отдельную копию репозитория для демонстрации: переключение на закреплённый коммит сохраняет проверенное поведение приложения.
Без API-ключа сразу доступны ручные условия, календарь, строгий подбор, объяснения и ближайшие варианты. Данные автоматически импортируются в PostgreSQL при первом запуске и сохраняются между перезапусками.
Включить диалог и диктовку через OpenAI
Создайте локальный файл настроек, если его ещё нет:
cp -n .env.example .env
Откройте .env в редакторе и задайте OPENAI_API_KEY. Затем остановите сервер через Ctrl+C и снова выполните:
go run .
Ключ хранится на сервере; .env исключён из Git. Текстовый диалог и диктовка не требуют подготовки смыслового индекса. Микрофон доступен на localhost или HTTPS при разрешении браузера. Аудио записывается до 60 секунд, расшифровка появляется в редактируемом поле.
Включить смысловую сортировку по пожеланиям
После настройки ключа:
go run . -prepare
go run .
Первая команда создаёт data/semantic-index.json: фиксированные числовые представления цитат и пожеланий. Если сервер уже работал, перезапустите его после подготовки. Файл не перезаписывается автоматически.
Для воспроизводимого смыслового порядка на другой машине нужен тот же файл индекса, а не его повторная генерация. Сохраните подготовленный индекс вместе с решением; ключей в нём нет. Пока индекс не подготовлен, интерфейс прямо сообщает о сортировке по начальной цене.
Статус представленной версии: текстовый диалог проверен через настоящий OpenAI API. Подготовка смыслового индекса реализована, но в текущем демо индекс отсутствует — порядок по цене. Диктовка реализована и проверена с искусственным микрофоном и подменённым ответом распознавания; качество настоящей транскрипции ещё нужно проверить отдельно.
Настройки внешней БД, переменные окружения и подробности сохранения данных — в техническом справочнике.
Где работает AI, а где — строгие правила
В проверенном Go-сценарии AI участвует до выдачи карточек: разбирается в идее мероприятия, уточняет специализацию и преобразует рассказ в поля и пожелания. Проверку обязательных условий выполняет Go. Поэтому красивое описание профиля не позволяет обойти бюджет или календарь.
flowchart TD
U["Рассказ или диктовка"] --> C["AI-консультант: смысл и уточнения"]
C --> R["Редактируемые условия и подтверждение"]
R --> F["Go: строгая проверка условий"]
DB[("PostgreSQL: каталог и занятость")] --> F
F -->|Есть совпадения| S["Смысловой индекс, если подготовлен; иначе цена"]
S --> E["До 3 карточек: проверенные факты и цитаты"]
F -->|Нет совпадений| N["Причины и ближайшие варианты"]
N -->|Пользователь меняет условия| R
| Слой | Реализация | Зачем |
|---|---|---|
| Интерфейс | HTML, CSS, обычный JavaScript | Один Go-сервер раздаёт готовый интерфейс; нет этапа фронтенд-сборки |
| Диалог | OpenAI Responses API, структурированный ответ | Извлечение условий и вопрос по контексту за один вызов |
| Голос | MediaRecorder → сервер → Transcriptions API | Диктовка с правкой текста и отдельным подтверждением |
| Подбор | Go, общие правила для поиска и календаря | Строгие ограничения одинаково работают во всех сценариях |
| Хранение | PostgreSQL 17, драйвер pgx | Постоянные данные, атомарный импорт, актуальная занятость |
| Смысл | Embeddings, фиксированный файл индекса | Сравнение пожеланий без нового вызова модели при сортировке |
| Объяснения | Проверенные поля + точная цитата | Конкретная причина выбора, которую можно сверить с каталогом |
Embeddings — числовые представления текстов для сравнения смысла. Первая версия использует 12 направлений пожеланий и одну проверенную цитату на профиль. Произвольные обязательные требования, например оборудование или вместимость, не превращаются в доказанные возможности подрядчика.
В Go-сценарии во время поиска по подтверждённым условиям внешняя языковая модель не вызывается. Ориентир ответа — до 10 секунд; это цель задания, а не заявленная гарантия под нагрузкой.
Python-модуль: поиск в актуальной версии
Команда добавила загрузку JSONL-каталога, фильтрацию, локальное сравнение пожеланий и генератор объяснений на Python. Интерфейс актуальной версии обращается к /api/search: Python ранжирует профили из PostgreSQL, а Go добавляет ближайшие варианты и даты из того же снимка данных. /api/matches сохраняет прежний Go-алгоритм. У этих путей разные сортировка и объяснения; подготовка Go-индекса не включает Python-поиск.
Исходники и инструкции обоих направлений сохранены. В техническом справочнике описаны запуск актуального сайта и отдельного Python-модуля, зависимости, контракт API и ограничения. Его результаты не выдаются за проверенные скриншоты и контрольные примеры ниже.
Почему повтор в Go-сценарии возвращает тот же порядок
При одинаковых подтверждённых условиях, пожеланиях, данных, коде и индексе сортировка фиксирована:
- Смысловая близость, если индекс подготовлен и пожелания выбраны.
- Начальная цена.
- Стабильный
idпри равенстве.
Порядок выбора пожеланий и их дубли не меняют результат. Изменение каталога делает старый индекс несовместимым. Сам свободный текст внешняя модель может разобрать по-разному — поэтому условия обязательно показываются для подтверждения. temperature=0 и кеш не выдаются за гарантию повторяемости.
Что защищает качество Go-подбора
| Требование кейса | Поведение EventMatch |
|---|---|
| Город, дата, формат, категория, бюджет | Обязательны и проверяются на сервере |
| Язык и длительность | Учитываются как строгие условия, если указаны |
| Занятый подрядчик | Исключается из совпадений, включая площадки |
| Меньше трёх подходящих | Показываем сколько есть и объясняем причину |
| Такой категории в городе нет | Отдельный исход category_unavailable |
| Категория есть, условия не проходят | Отдельный исход no_matches |
| Конкретные объяснения | Цитата профиля и факты соответствия, а не универсальные похвалы |
| Неизвестные условия | Явное уточнение или решение пользователя; молчаливого удаления нет |
| Ближайший вариант | Все несовпадения раскрыты; он не становится строгим совпадением |
Важные различия: цена «от» не равна итоговой стоимости; отсутствие отметки о занятости не гарантирует бронирование; смысловая близость не подтверждает услугу; другой город не означает возможность выезда.
Проверка для жюри · пять минут
В AI-консультанте есть кнопки готовых примеров: они открывают подтверждение, а не обходят проверки. Таблица ниже проверена на версии ab45c2c и исходном каталоге; для точного порядка оставьте пожелания пустыми.
| Шаг | Что проверить | Условия и ожидаемый результат |
|---|---|---|
| 1 | Массовая категория | Алматы · ведущий · корпоратив · 06.10.2026 · 1 300 000 ₸ · русский · 6 ч. Семь совпадений; карточки: Куррапика → Мицури Канроджи → Аня Форджер |
| 2 | Повтор и смена даты | Повторить шаг 1: тот же порядок. Изменить только дату на 02.10.2026: Кики и Буллма; прошлые варианты исключены по занятости |
| 3 | Редкая категория | Астана · флорист · свадьба · 01.10.2026 · 300 000 ₸ · русский. Единственный вариант — Хаку |
| 4 | Занятость и ближайшие дни | Для Хаку выбрать 02.10.2026. Совпадений нет; среди альтернатив — Хаку с датами 03.10, 01.10, 30.09. Выбор даты требует подтверждения |
| 5 | Пустая выдача с несколькими причинами | Алматы · фото и видеобудки · день рождения · 23.09.2026 · 10 000 ₸. Совпадений нет; отдельно Кадзума Сато, Аква, Аска Ленгли с объяснением различий |
| 6 | Отсутствующая категория | Астана · декоратор · свадьба · 01.10.2026 · 2 000 000 ₸. Отдельное сообщение: такой категории в городе нет |
Для живого AI-сценария: «Хочу оформить свадьбу в Алматы 10 октября 2026. До 300 000 тенге на специалиста, но не знаю, кто нужен». Уточните «цветы и букеты» и проследите, как заполняются поля. Или попросите фотографа и выберите репортажный стиль. Непроверяемое «обязательно без конкурсов» должно остаться для отдельного решения перед поиском.
Тот же подбор одним API-запросом
curl http://localhost:8080/api/matches \
-H 'Content-Type: application/json' \
-d '{"city":"Алматы","event_date":"2026-10-06","event_type":"корпоратив","category":"Ведущий","budget_kzt":1300000,"language":"русский","duration_hours":6,"wishes":[],"unverified_requirements":[]}'
Ответ содержит status, cards, число совпадений, причины исключения, способ сортировки, версию данных и отдельные альтернативы. Описание API-маршрутов Go-сценария — в справочнике.
Проверки и воспроизводимость
Команды и результаты в этом разделе относятся к закреплённой Go-версии ab45c2c. Проверки нового Python-модуля описаны отдельно.
go test -race ./...
go vet ./...
Обычные Go-тесты не обращаются к внешнему AI. Они проверяют ограничения, происхождение цитат, три исхода, ближайшие варианты, повторяемость, ошибки провайдера и фиксированный смысловой индекс на контрольных векторах.
| Проверка | Что доказывает |
|---|---|
| main_test.go, alternatives_test.go | Строгие условия, объяснения, редкие категории, лимит карточек и порядок альтернатив |
| calendar_test.go | Календарь и подбор согласуются на всех 100 днях, границы периода и ближайшие даты проверены |
| consultation_test.go | Контекст диалога, обязательные поля, необязательный стиль, валидация и сбои AI |
| database_test.go | Атомарный импорт, сохранность изменений, одновременные старты и актуальность БД |
| voice_test.go | Формат и размер записи, ошибки распознавания, отсутствие ключа |
| ui_consultation_check.py, ui_requirements_check.py | Браузерный сценарий, ручные правки, отказ/повтор, явное согласие, адаптивность и анимации |
Запустить проверки PostgreSQL и интерфейса
Для интеграционной проверки с локальной БД по умолчанию:
docker compose up -d --wait db
TEST_DATABASE_URL='postgres://eventmatch:[email protected]:5432/eventmatch?sslmode=disable' go test -race ./...
Тест создаёт и удаляет свою отдельную БД; требуется право CREATE DATABASE. Рабочий каталог не очищается. Без TEST_DATABASE_URL интеграционная проверка пропускается. При собственных настройках используйте соответствующий адрес БД.
При запущенном приложении, с установленными Firefox и uv:
uv run --with selenium python ui_consultation_check.py
uv run --with selenium python ui_requirements_check.py
Selenium устанавливается во временное окружение uv, не в зависимости приложения. В этих сценариях ответы AI подменяются; каталог, календарь и подбор работают через настоящий локальный сервер.
Данные, которым можно проследить источник
Для показанного Go-сценария каталог — исходный CSV организаторов: 66 профилей, 17 категорий. Это 50 профилей Алматы, 15 Астаны и один с городом «Зарубежье». Данные из сокращённого HTML-превью не используются.
- 13 синтетических профилей организаторов, 8 дополненных городов и 18 дополненных цен сохраняют исходные флаги. Их происхождение видно в интерфейсе; добавлений команды в рабочем каталоге нет.
- Цитаты проверяются на буквальное присутствие в описании. Это отобранные фрагменты, а не придуманные сведения о подрядчиках.
max_hours = nullозначает, что услуга не привязана к присутствию на площадке. Это допустимо, а не повод исключить флориста или декоратора.- Календарь известен только за 23.09.2026–31.12.2026. За его границами доступность не предполагается.
В проверенной Go-версии PostgreSQL хранит профили, занятость, цитаты и происхождение. Повторный запуск не затирает изменения, а каждый новый запрос читает актуальный каталог.
Границы версии и развитие
Текущая версия предназначена для локальной демонстрации. Публичного развёртывания и подтверждённого доступа к API Firebird нет. Бронирование, оплата и уведомления подрядчикам не входят в реализованный сценарий.
Диалог и форма живут в памяти вкладки: обновление страницы их сбрасывает. История ограничена 11 ответами пользователя, затем можно продолжить вручную. Ключи остаются на сервере; тексты и аудио не записываются приложением в БД или файлы, но отправляются OpenAI для обработки. Первичный разбор AI требует проверки человеком.
Следующие шаги: проверить качество реальной транскрипции и смыслового индекса; расширить проверяемые характеристики специалистов; добавить актуализацию занятости из подтверждённого источника; оценить качество рекомендаций на размеченных запросах. Сохранение проектов мероприятий и публичное размещение — отдельные этапы с настройкой доступа и ограничением расходов API.
Сделано командой Soda для HackAlem AI
AI-агент разработки — Codex: реализация, проверки, работа с цитатами и документация.
Полная техническая документация ·
Изменения проекта ·
Запуск
Авторы коммитов
История коммитов
- 2026-09-23 17:32Merge pull request #4 from BAITC-Hacks/feat/catalog-aiMiras Zhumazhan
- 2026-09-23 17:30Merge main and reconcile README with the integrated Python searchMiras Zhumazhan
- 2026-09-23 17:09Present EventMatch with a visual README and real product screenshotsMiras Zhumazhan
- 2026-09-23 16:42Merge pull request #2 from BAITC-Hacks/feat/catalog-aiMiras Zhumazhan
- 2026-09-23 16:39Add contextual AI consultation and accessible interface motionMiras Zhumazhan
- 2026-09-23 16:23Offer nearest catalog alternatives with explicit constraint differencesMiras Zhumazhan
- 2026-09-23 17:18Fix merged app startup, UI and live PostgreSQL searchZack-MV
- 2026-09-23 16:13Make unresolved requirements explicit and actionable before matchingMiras Zhumazhan
Все коммиты (19)
- 2026-09-23 17:05Merge pull request #3 from BAITC-Hacks/feat/ai-event-matchingZack-MV
- 2026-09-23 17:05Merge branch 'main' into feat/ai-event-matchingZack-MV
- 2026-09-23 15:58Redesign EventMatch and add occupancy calendar with date alternativesMiras Zhumazhan
- 2026-09-23 16:53feat: Implement CORS and logging middleware for improved API handlingZack-MV
- 2026-09-23 15:10Add persistent PostgreSQL catalog and editable voice dictationMiras Zhumazhan
- 2026-09-23 15:03Merge pull request #1 from BAITC-Hacks/feat/catalog-aiMiras Zhumazhan
- 2026-09-23 14:47feat: connect EventMatch to organizer catalog and confirmed AI preferencesMiras Zhumazhan
- 2026-09-23 15:46feat: add AI event matching pipelineZack-MV
- 2026-09-23 14:01docs: describe contractor selection concept and project statusMiras Zhumazhan
- 2026-09-23 14:17Rename README.md to README_CSS_HTML.mdZhasmina
- 2026-09-23 14:16css, htmlZhasmina
Структура репозитория (49 файлов)
.env.example .gitattributes .gitignore README.md Soda_UI/EventMatch/README_CSS_HTML.md ai.go alternatives.go alternatives_test.go calendar.go calendar_test.go compose.yaml consultation.go consultation_test.go data/catalog.csv data/evidence.json data/hackathon-dataset-anonymized.jsonl database.go database_test.go docs/TECHNICAL.md docs/images/alternatives.png docs/images/calendar.png docs/images/consultation.png docs/images/home.png docs/images/mobile.png docs/images/readme-cover.svg docs/images/results.png go.mod go.sum main.go main_pipeline.py main_test.go pipeline_api.py requirements.txt schema.sql search.go server_test.go src/__init__.py src/data_loader.py src/filters.py src/generator.py src/ranker.py tests/__init__.py tests/test_e2e_pipeline.py tests/test_pipeline_api.py tests/test_ranker.py ui_consultation_check.py ui_requirements_check.py voice.go voice_test.go
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.

