AAYMA
RU
Войти

ToiTap

Веб-сервис подбора до 3 подрядчиков для мероприятия по свободному текстовому запросу, с объяснением выбора к каждой карточке и избранным.

Доведённый продукт
Команда «Qadam Tech» 10💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Qadam Tech
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт

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

Суть

Веб-сервис подбора до 3 подрядчиков для мероприятия по свободному текстовому запросу, с объяснением выбора к каждой карточке и избранным.

Как устроено

/api/parse через OpenAI (structured output) извлекает город, дату, формат, категорию, бюджет; если AI не справился, недостающее дополняет разбор по правилам. Backend на pandas фильтрует 66 профилей из CSV по городу, категории, занятости, цене, формату, языку и длительности и детерминированно ранжирует их (упоминание формата, полнота данных, запас бюджета, при равенстве по ID). LLM получает только отобранных кандидатов и пишет объяснения на фактах, порядок не меняет. При сбое срабатывают шаблоны, повторные запросы кэшируются.

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

  • LLM query parsing
  • rule-based fallback parser
  • deterministic scoring
  • hard-filter eligibility
  • structured outputs
  • in-memory cache

Особенности

Жёсткое разделение: LLM только разбирает запрос и формулирует объяснения, а отбор и порядок задаёт воспроизводимый алгоритм. Флаги source/explanation_source показывают, что сделал AI. Сервис различает «категории нет в городе» и «нет подходящих кандидатов». Есть живой деплой и Docker-first запуск.

Стек

Python · FastAPI · Pydantic · pandas · React 19 · TypeScript · Vite · Tailwind CSS · Docker Compose · Nginx · pytest

Модели

gpt-4.1-mini


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

README

README.md

ToiTap

Подрядчики для вашего мероприятия.

Сайт: toi-tap.aribzhan.kz

React 19 · TypeScript · FastAPI · OpenAI

Хакатон-проект команды Qadam Tech.

Быстрый старт · Как работает AI · Демо-запросы · Backend API

ToiTap помогает найти подрядчиков для мероприятия: расскажите о планах обычным текстом, получите до трёх подходящих вариантов и узнайте, почему каждый из них оказался в подборке.

Вместо длинного каталога — короткий список с конкретными фактами: стоимость, доступность, язык, длительность и детали из описания профиля.

Хакатон-проект Qadam Tech, задача #79-lite. Каталог содержит 66 анонимизированных профилей, включая 13 синтетических. Это демонстрационный подбор, без бронирования и оплаты. Фотографии иллюстрируют категории услуг и не изображают конкретных подрядчиков.

Preview

ToiTap — подбор подрядчиков для вашего мероприятия

Интерфейс адаптируется к размеру экрана: одна колонка карточек на телефоне, две на планшете, три на широком экране. Проверены ширины 320, 375, 390, 768, 1024 и 1440 px, включая открытый календарь. Это проверка размеров viewport, а не сертификация всех устройств и браузеров.

Возможности

  • Поиск обычным текстом. Город, дата, формат, категория и бюджет извлекаются из запроса; язык и длительность можно уточнить дополнительно.
  • До трёх рекомендаций. Занятые на дату, превышающие бюджет и не подходящие под условия профили исключаются до формирования подборки.
  • Объяснение к каждой карточке. Цена относительно бюджета, особенности предложения и факты из описания помогают сравнивать варианты.
  • Понятный пустой результат. Сервис различает отсутствие категории в городе и отсутствие подходящих кандидатов; показывает причины исключения.
  • Личный список. Избранное открывается отдельным представлением без баннера, поиска и фильтров. Сохранение — в localStorage этого браузера.
  • Карточка профиля. Описание, языки, форматы, стартовая цена и ограничения по времени доступны в модальном окне.
  • Светлая и тёмная темы. Адаптивный интерфейс с локальными тематическими фотографиями, календарём и фильтрами.
  • Работа без AI-ключа. Разбор по правилам и шаблонные объяснения сохраняют доступность поиска.

Дизайн

Светлый фон, глубокий зелёный акцент, типографика Manrope и крупные фотографии создают спокойный интерфейс для планирования события.

ЭлементЗначение
Основной фон#FAFBF8
Акцент и основные действия#075B43
Основной текст#203B31
Мягкие поверхности#F1F5EF
ШрифтManrope

Фотографии хранятся в frontend/public/images и загружаются с самого приложения. На карточках они отмечены как изображения для вдохновения. Шрифт загружается через Google Fonts; при недоступности используется системный sans-serif.

Designed by Qadam Tech.

Как работает AI

flowchart LR
    A[Описание события] --> B[AI: извлечение параметров]
    B --> C[Backend: фильтры и ранжирование]
    C --> D[До 3 кандидатов]
    D --> E[AI: объяснения на фактах]
    E --> F[Карточки и избранное]
  1. Понимает запрос. /api/parse преобразует текст в структурированные параметры. Значения приводятся к категориям каталога; недостающие распознанные значения дополняются разбором по правилам.
  2. Отбирает по условиям. Backend проверяет город, категорию, занятость, цену, формат, язык и максимальную длительность.
  3. Ранжирует воспроизводимо. Порядок определяет алгоритм: упоминание формата в описании, полнота исходных данных, запас бюджета, язык и часы. При равном балле используется ID.
  4. Объясняет выбор. OpenAI получает только отобранные профили и факты для объяснения. AI не выбирает кандидатов и не меняет их порядок.
  5. Обрабатывает сбои. При ошибке или таймауте AI используются правила и шаблоны. Повторные запросы кэшируются в памяти backend.

Поле source: "llm" подтверждает AI-разбор, а explanation_source: "llm" — AI-объяснение конкретной карточки. В интерфейсе это отдельные индикаторы. /api/health с llm: true означает наличие ключа, но не гарантирует успешный ответ модели.

Модель по умолчанию — gpt-4.1-mini. Изменить её и таймаут можно в локальном .env.

Данные и ограничения

  • 66 профилей, 17 категорий, города каталога: Алматы, Астана и «Зарубежье».
  • Доступное окно дат: 23 сентября — 31 декабря 2026 года.
  • Синтетические профили отмечены; восстановленные цены отображаются как ориентировочные.
  • Стоимость — начальная цена услуги, не подтверждённая итоговая смета.
  • max_hours: null означает отсутствие ограничения по часам присутствия.
  • Если никто не подходит, условия автоматически не смягчаются. Нужно изменить бюджет, дату, формат или категорию.
  • Неуказанные в новом тексте параметры сохраняются из текущих фильтров. Перед независимым сценарием проверьте язык и длительность.
  • Избранное хранит результат прошлого поиска: доступность нужно проверять повторно.
  • Объяснения AI требуют проверки: возможны неточности формулировок и сравнения цен.

Быстрый старт

Основной способ запуска — Docker Compose: frontend с Nginx и backend FastAPI поднимаются одной командой. Нужны Git, Docker Engine / Docker Desktop и Docker Compose 2.24+. Локальные Python, Node.js и npm для запуска не требуются.

1. Получите проект

git clone --branch main [email protected]:BAITC-Hacks/hack-c1535a6c-qadam-tech.git
cd hack-c1535a6c-qadam-tech

Для клонирования нужен доступ к репозиторию и SSH-ключ, добавленный в GitHub. Если проект уже скачан, откройте его папку.

2. Настройте AI

Без ключа поиск работает по правилам и возвращает шаблонные объяснения. Для OpenAI создайте файл, только если его ещё нет:

if [ ! -f backend/.env ]; then
  cp backend/.env.example backend/.env
fi
chmod 600 backend/.env
nano backend/.env

Заполните OPENAI_API_KEY. Параметры OPENAI_MODEL и OPENAI_TIMEOUT задают модель и таймаут в секундах. Существующий .env сохраните: ключ не нужно переносить в Dockerfile или frontend.

3. Соберите и запустите

Запустите Docker Desktop, если используете его, затем выполните из корня проекта:

docker compose up -d --build --wait

Frontend обращается к /api через Nginx в контейнере. Backend доступен внутри сети Compose; его порт не публикуется на хост. Первый запуск скачивает образы и устанавливает зависимости, последующие используют кэш.

Управление

Все команды выполняются из корня проекта:

# Состояние контейнеров
docker compose ps

# Логи в реальном времени; Ctrl+C завершает просмотр логов
docker compose logs -f

# Остановка и удаление контейнеров; исходники и .env сохраняются
docker compose down

# Повторный запуск
docker compose up -d --wait

# Пересборка после изменения кода
docker compose up -d --build --wait

# Применение изменений backend/.env
docker compose up -d --force-recreate --wait backend

Для запуска с логами в текущем терминале используйте docker compose up --build; в этом режиме Ctrl+C останавливает контейнеры. Если порт 8080 занят, задайте другой: TOITAP_PORT=8081 docker compose up -d --build --wait.

Ubuntu и HTTPS

На сервере Docker также слушает 127.0.0.1:8080. Внешний Nginx направляет запросы домена в контейнер, а Certbot продолжает обслуживать HTTPS на хосте.

Инструкция по настройке, переходу с systemd и откату · Пример Nginx для домена.

Для разработки без Docker запустите backend по его инструкции, затем выполните npm ci и npm run dev в папке frontend (Node.js 22.12+). Vite открывается на порту 5173 и направляет /api на backend порта 8765.

Демо-запросы

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

ЗапросОжидаемый результат
Нужен ведущий на свадьбу в Алматы 15 октября 2026 года, бюджет до 1 500 000 тенге.Кики, Эмилия, Мицури Канроджи — 3 карточки
Нужен флорист на свадьбу в Алматы 14 ноября 2026 года, бюджет до 500 000 тенге.Тихиро Огино — 1 карточка, второй флорист занят
Нужен отель для свадьбы в Алматы 30 сентября 2026 года, бюджет до 3 500 000 тенге.Гохан — 1 карточка, от 3 200 000 ₸
Нужен декоратор на свадьбу в Астане 14 ноября 2026 года, бюджет до 3 000 000 тенге.Категории нет в городе

Техническая структура

СлойТехнологии и ответственность
FrontendReact 19, TypeScript, Vite, Tailwind CSS, Lucide
APIFastAPI, Pydantic, Uvicorn
ПодборPython, pandas, CSV → JSON-кэш, детерминированный скоринг
AIOpenAI Responses API, структурированный вывод, fallback и кэш
Проверкиpytest, Node.js test runner, TypeScript и production build
compose.yaml           Запуск frontend и backend
docker/                Инструкции, smoke-тест и конфигурация хостового Nginx
backend/
  Dockerfile           Образ FastAPI
  app/main.py          API и валидация
  app/data.py          Загрузка и нормализация каталога
  app/search.py        Фильтрация, причины исключения, скоринг
  app/llm.py           AI-интеграция, кэш и fallback
  app/ai/              Промпты, разбор запроса и объяснения
  data/dataset.csv     Исходные данные
  tests/               Тесты подбора и AI-модуля
frontend/
  Dockerfile           Сборка React и образ Nginx
  nginx.conf           Статика и проксирование /api
  public/images/       Статические иллюстрации категорий
  src/main.tsx         Поиск, карточки, избранное и темы
  src/api.ts           Контракты API и проверка параметров
  src/DatePicker.tsx   Календарь
  src/style.css        Визуальная система

Проверки

После запуска контейнеров проверьте API:

curl -fsS http://127.0.0.1:8080/api/health

Полная проверка frontend → Nginx → backend, изображений, подбора и разбора текста требует Python 3 на хосте, без дополнительных пакетов:

python3 docker/smoke.py

Backend-тесты можно выполнить внутри Docker из корня проекта:

docker compose run --rm --no-deps -e OPENAI_API_KEY= \
  -v "$PWD/backend/tests:/app/tests:ro" \
  backend python -m pytest -q -p no:cacheprovider

Текущий набор: 22 backend-теста и 4 frontend-теста. Frontend-тесты, TypeScript и production build выполняются при сборке frontend image. Unit-тесты не заменяют проверку реального OpenAI-запроса: smoke-тест выводит источники разбора и объяснений, включая переход на шаблоны.

Конфигурация и приватность

backend/.env исключён из Git правилами .gitignore. В репозитории хранится только .env.example без ключа. .dockerignore исключает секреты из контекста сборки; Compose передаёт переменные backend при запуске контейнера. API-ключ используется исключительно backend и не должен попадать в frontend, скриншоты или коммиты.

С включённым AI текст запроса и данные выбранных профилей отправляются в OpenAI; клиент указывает store=False. Избранное и выбранная тема сохраняются локально в браузере. Сервис не реализует регистрацию, бронирование, оплату или отправку сообщений подрядчикам.

Дальнейшее развитие

  • Подбор с учётом условий и занятости
  • AI-разбор текста и объяснения с fallback
  • Избранное, темы и адаптивные карточки
  • Улучшение сравнений цен в AI-объяснениях
  • Явное уведомление при переходе на шаблон после таймаута
  • Предложение альтернативных условий при пустом результате

Команда и материалы

Qadam Tech — backend и данные, frontend и дизайн, AI-интеграция.

Фотографии: Unsplash. Источники локальных изображений перечислены в frontend/public/images/README.md.

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

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

jahongirdev1 7Aribzhan 4Akhror 1

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

  • 2026-09-23 17:50Add Docker Compose deployment and Docker-first READMEAribzhan
  • 2026-09-23 17:30docs: add live website link to READMEAribzhan
  • 2026-09-23 16:55Polish responsive UI and favorites, add project showcase READMEAribzhan
  • 2026-09-23 15:35Track generated candidates.jsonjahongirdev1
  • 2026-09-23 15:33Replace native date picker and selects with branded controlsjahongirdev1
  • 2026-09-23 15:30Improve LLM explanations and query parsingjahongirdev1
  • 2026-09-23 15:24Integrate backend, AI engine and frontend into one appjahongirdev1
  • 2026-09-23 15:17Merge remote-tracking branch 'origin/frontend' into integrationjahongirdev1
Все коммиты (12)
  • 2026-09-23 15:17Merge remote-tracking branch 'origin/feature/ai-engine' into integrationjahongirdev1
  • 2026-09-23 15:13feat: add AI query parser and contractor explanationsAkhror
  • 2026-09-23 15:04feat: add ToiTap frontend with contractor matching and themesAribzhan
  • 2026-09-23 14:34Add FastAPI backend for contractor matchingjahongirdev1
Структура репозитория (49 файлов)
.gitignore
README.md
backend/.dockerignore
backend/.env.example
backend/Dockerfile
backend/README.md
backend/app/__init__.py
backend/app/ai/__init__.py
backend/app/ai/client.py
backend/app/ai/explainer.py
backend/app/ai/parser.py
backend/app/ai/prompts.py
backend/app/data.py
backend/app/explain.py
backend/app/llm.py
backend/app/main.py
backend/app/rules_parser.py
backend/app/search.py
backend/data/candidates.json
backend/data/dataset.csv
backend/demo.py
backend/requirements.txt
backend/tests/test_ai.py
backend/tests/test_pipeline.py
compose.yaml
docker/README.md
docker/nginx-host-location.conf.example
docker/smoke.py
docs/images/toitap-banner.png
frontend/.dockerignore
frontend/Dockerfile
frontend/index.html
frontend/nginx.conf
frontend/package-lock.json
frontend/package.json
frontend/public/images/README.md
frontend/public/images/celebration.jpg
frontend/public/images/entertainment.jpg
frontend/public/images/flowers.jpg
frontend/public/images/photography.jpg
frontend/public/images/venue.jpg
frontend/src/DatePicker.tsx
frontend/src/api.test.ts
frontend/src/api.ts
frontend/src/main.tsx
frontend/src/style.css
frontend/src/vite-env.d.ts
frontend/tsconfig.json
frontend/vite.config.ts
Ветки (4)

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

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

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