AAYMA
RU
Войти

Contractor Matcher

Подбор до трёх event-подрядчиков: детерминированные фильтры и ранжирование, а два необязательных LLM-слоя на Groq разбирают свободный текст запроса…

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

О проекте

Команда: Anomaly Detected
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP

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

Суть

Подбор до трёх event-подрядчиков: детерминированные фильтры и ранжирование, а два необязательных LLM-слоя на Groq разбирают свободный текст запроса и переписывают объяснения. Покрыто 95 тестами, интерфейс на RU/KZ/EN.

Как устроено

FastAPI с эндпоинтом POST /api/match. Python фильтрует по городу, категории, формату, бюджету, дате, языку и длительности и ранжирует по бюджету, уверенности в данных и релевантности. Слой 1 (intent_parser) сопоставляет свободный текст с реальными категориями и языками датасета, результат идёт в ранжирование как мягкий сигнал. Слой 2 (llm_explainer) переписывает текст объяснений уже выбранных карточек; ответ сверяется с id и полями подрядчика, при ошибке используется шаблон. Статусы none_fit и no_category сопровождаются разбивкой причин отказа и воронкой отсева.

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

  • constraint-based recommender
  • deterministic ranking
  • LLM intent parsing
  • LLM explanation rewriting with validation
  • template fallback

Особенности

Литобзор обосновывает выбор constraint-based рекомендателя. Отдельные тесты проверяют, что AI никогда не меняет состав и порядок карточек. На фронтенде есть демо-режим на mock-ответах, работающий без бэкенда, и сравнение одного запроса на двух датах.

Стек

Python · FastAPI · Pydantic · pytest · Vanilla JavaScript · HTML/CSS

Модели

openai/gpt-oss-120b (Groq)


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

README

README.md

Contractor Matcher

Smart Contractor Matching for Event Vendors

Команда Anomaly Detected · HackAlem AI · Track 06 Creative Industries · кейс «Smart contractor matching» (Firebird)

Детерминированная фильтрация и ранжирование • AI не выбирает подрядчика • Понимание запроса и объяснения — опциональный слой Groq


Python FastAPI Groq Pydantic

Vanilla JS Pytest UI

Track Status



Video Demo

video/Untitled Project.mp4


Ссылки

ЧтоГде
Репозиторий[email protected]:BAITC-Hacks/hack-2cc01208-anomaly-detected.git
Контракт APIdocs/api.md
Условие задачиdocs/task.md
Литературный обзорdocs/literature-review.md

Проблема

Площадка-агрегатор event-подрядчиков в Казахстане уже показала заказчику каталог по его городу — но каталог сам по себе не решение, это просто более длинный список. Задача не «найти подрядчиков», а «помочь выбрать из уже найденных»: заказчик не должен вручную сверять бюджет, занятость на дату, формат мероприятия и язык для каждой из десятков карточек подряд.

Решение

Пользователь-заказчик мероприятия вводит параметры (город, дата, тип события, категория подрядчика, бюджет, опционально — язык, длительность и свободный текст запроса) и получает до 3 карточек подрядчиков из каталога, каждая — с конкретным объяснением, почему именно этот подрядчик подходит. Ценность решения — в объяснении, а не в самой сортировке: это прямо прописано в условии задачи.

Главный архитектурный принцип: AI не выбирает победителя. Кто подходит, в каком порядке и с каким счётом — решает детерминированный Python-код. AI (Groq) используется только там, где это не меняет результат: разбор свободного текста в структурированные метки и переписывание текста уже выбранных объяснений.


Почему такая архитектура

Коротко, три шага (полный разбор с APA-цитатами — docs/literature-review.md):

Рекомендации подрядчиков в двусторонних сервис-маркетплейсах — изученная, экономически значимая задача (Shi, 2024). При тонком датасете без истории взаимодействий (66 профилей, без рейтингов) знание-based / constraint-based рекомендеры — устоявшийся ответ именно на такой случай: они не страдают от cold-start и объясняют отказ даже когда решения нет (Burke, 2000; Felfernig & Burke, 2008) — прямое обоснование, почему none_fit/no_category в этом проекте полноправные, объяснённые статусы API, а не пустой ответ. В домене event-подрядчиков уже есть публикации, которые считают числовой скор, но не генерируют объяснение (Singh et al., 2020) — ровно то, что кейс просит исправить. А использование LLM именно для объяснения уже выбранной рекомендации — редкий паттерн: всего 6 из 232 статей в обзоре 2025 года реально так делают (Said, 2025), и именно поэтому нужна валидация вывода — LLM-текст без проверки является известным источником галлюцинаций (Ji et al., 2023), так что Groq здесь никогда не выбирает и не переупорядочивает карточки, только переписывает уже готовый текст, и этот текст сверяется с реальными полями подрядчика перед показом.

Related Work

РаботаКто решает, что подходитОткуда объяснениеОбъясняет ли нулевой результатЗащита от галлюцинаций
Burke (2000); Felfernig & Burke (2008) — constraint-based рекомендерыСимвольный решатель ограниченийФормируется из правилДа, по определению подходаНе применимо (без LLM)
Singh et al. (2020) — event-planning рекомендерГибридный контент+соц. скорНе генерируетсяНетНе применимо
Shi (2024) — матчинг в двусторонних маркетплейсахОптимизированная политика по конверсииНе часть моделиНетНе применимо
Said (2025) — обзор LLM-объяснений рекомендацийОбычно отдельная модельТекст LLMПочти не рассматривается в обзореНе унифицировано между 6 работами
Contractor Matcher (этот проект)Python: детерминированный фильтр + скоринг, всегдаGroq, только текст, только для уже выбранных карточекДа — none_fit/no_category с разбивкой excludedДа — валидация по реальным id/полям, fallback на шаблон

Два AI-слоя: до поиска и после

AI используется в двух разных, не пересекающихся местах пайплайна — и оба спроектированы так, чтобы не менять итог поиска, только качество взаимодействия с ним.

Слой 1 — до поиска (intent_parser.py): понимание запроса, а не поиск по ключевым словам. Обычный keyword-поиск ищет буквальное совпадение слов. Проблема в том, что реальный пользователь формулирует запрос не терминами каталога: он может написать «нужен человек, который снимет видео с мероприятия» и ни разу не произнести слово «видеограф». Поиск по ключевым словам такой запрос не поймёт — а пользователю нужно ровно это. Этот AI-слой читает свободный текст и сопоставляет его с реальными категориями/языками/форматами из датасета (никогда не выдумывая новые), примерно так же, как это сделал бы человек-администратор каталога, читающий заявку. Результат — мягкий сигнал для ранжирования (или жёсткий фильтр только для явно обязательного языка, «должен говорить на казахском»), а не решение: Python по-прежнему фильтрует и сортирует сам.

Слой 2 — после поиска (llm_explainer.py): объяснение уже готового результата. Когда Python уже выбрал до 3 карточек, Groq только переписывает текст объяснения для каждой — понятным, неповторяющимся языком вместо сухого перечисления полей. Состав карточек, их порядок и цена не меняются. Ответ модели проверяется по id и реальным полям подрядчика; любая неудача (таймаут, ошибка, невалидный JSON) откатывается на детерминированный шаблон.

Итог: один AI-слой помогает понять, что на самом деле хочет пользователь, а не механически искать слова; другой — объяснить уже честно найденный результат по-человечески. Ни один из них не может подменить решение детерминированного движка.


Возможности

  • Детерминированная фильтрация по городу, категории, формату события, бюджету, занятости на дату, языку и длительности
  • Детерминированное ранжирование по бюджету, уверенности в данных и релевантности категории/описания — без модели
  • Опциональный слой Groq поверх уже готового результата: переписывает только текст объяснения (валидируется по id, без выдуманных чисел, с fallback на шаблон при любой ошибке/таймауте)
  • Опциональный разбор свободного текста запроса («нужен фотограф и видеограф») в структурированные метки — мягкий сигнал для ранжирования, не фильтр (кроме явно обязательного языка)
  • Структурированная причина отказа (excluded) для каждого не прошедшего фильтр — всегда в ответе, включая found
  • Демо-режим на фронтенде: работает вообще без бэкенда, на заранее просчитанных mock-ответах — для показа жюри без риска сетевых сбоев
  • Сравнение одного запроса на двух датах бок о бок — наглядно показывает, что разница именно в занятости
  • Для none_fit — разбивка условий по карточкам «какое условие сколько кандидатов отсеяло» и визуальная воронка отсева; для no_category — предложение соседних городов, где категория есть
  • 95 тестов: 422 на невалидный ввод, детерминизм, «AI никогда не меняет состав/порядок карточек» — проверено явно, а не предполагается

🛠 Technologies We Used

The stack is deliberately simple — every piece earns its place, nothing is there for show.

  • Python — the filtering and ranking logic. This is the part that actually decides who gets recommended.

  • FastAPI — turns that Python logic into an API the frontend can call:

    Frontend
       ↓
    POST /api/match
       ↓
    Backend (filter → rank → explain)
       ↓
    Results
    
  • Groq API — fast inference access to an LLM, used only where explained in Два AI-слоя above.

  • openai/gpt-oss-120b — the model behind both AI layers: understanding free-text requests and writing the explanation text (DEFAULT_MODEL in backend/llm_explainer.py, overridable via GROQ_MODEL).

  • CSV — data/hackathon_dataset.csv stores the partner-provided contractor dataset: 66 real profiles.

  • Pydantic — validates every incoming request (backend/models.py, backend/frontend_api.py): rejects invalid dates, non-positive budgets, and out-of-range values before they ever reach the matching logic.

  • Pytest — 95 automated tests covering filtering, ranking, the AI layers (with dependency-injected fakes, no real API calls needed), and the API contract itself.

  • HTML + CSS + JavaScript — the frontend, no build step, no framework.

  • Git + GitHub — how the team stores the code, collaborates across three members, and submits the project.


Архитектура

flowchart TD
    U["🧑 Заказчик мероприятия"] --> F["🖥️ Frontend<br/>index.html + app.js + style.css<br/>+ Демо-режим на mock.js"]
    F -->|"POST /api/match"| B["⚡ FastAPI Backend"]
    F -->|"GET /api/options"| B

    B --> P{"Есть query<br/>(свободный текст)?"}
    P -->|"да, ENABLE_LLM_INTENT"| INT["🧭 Groq: разбор намерения<br/>услуги / язык / тип события"]
    P -->|"нет"| MATCH
    INT -->|"только валидные метки<br/>из датасета"| MATCH

    MATCH["📋 Детерминированный движок<br/>backend/matcher.py + relevance.py"]
    MATCH --> D1["Жёсткие фильтры<br/>город · категория · формат · бюджет · дата · язык · часы"]
    D1 --> D2{"Есть кандидаты?"}
    D2 -->|"пул пуст"| S1["status: no_category"]
    D2 -->|"пул не пуст, 0 подошло"| S2["status: none_fit + excluded"]
    D2 -->|"да"| RANK["Скоринг и сортировка<br/>budget · confidence · relevance"]
    RANK --> TOP["Топ-3, (score desc, id asc)"]

    TOP --> EXP{"ENABLE_LLM_EXPLANATIONS?"}
    EXP -->|"да"| GROQ["🤖 Groq переписывает текст<br/>только для уже выбранных 3 карточек"]
    EXP -->|"нет / ошибка / таймаут"| TMPL["Шаблонное объяснение<br/>из реальных полей"]
    GROQ -->|"валидация: id, без выдумок"| S3
    TMPL --> S3["status: found<br/>+ cards[] + excluded{}<br/>+ X-Explanations: llm|template|mixed"]

    B -.reads.-> DATA[("📄 hackathon_dataset.csv<br/>66 профилей")]

    S1 --> F
    S2 --> F
    S3 --> F

Два эндпоинта поверх одного и того же движка:

  • POST /match — детальный эндпоинт для разработчиков: полный score_breakdown, limit, поле services.
  • POST /api/match — адаптер под контракт фронтенда (docs/api.md): те же первые 3 результата /match, только переименованные поля и оформленный ответ. Покрыто тестами напрямую: для эквивалентных запросов cards — ровно первые 3 результата /match в том же порядке.

Скриншоты

Пустая форма

Списки городов/категорий/форматов/языков подтягиваются с GET /api/options.


Найдены подходящие подрядчики (status: found)

Нумерованные карточки с объяснением на реальных фактах и честным счётчиком «подходят N из M кандидатов».


Прозрачность подбора

Сколько кандидатов отсеяно и по какой причине — раскрывается для любого исхода, не только для пустого.


Кандидаты есть, но никто не подошёл (status: none_fit)

Сайдбар «Заданные условия» подсвечивает, какое именно условие (дата, бюджет...) сколько кандидатов отсеяло, плюс визуальная воронка отсева по всем причинам.


Такой категории нет в этом городе (status: no_category)

Третий обязательный по условию задачи исход — явно отличим от двух других, с предложением попробовать соседний город.


Сравнение с другой датой

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


Структура репозитория

hack-2cc01208-anomaly-detected
│
├── backend
│   ├── main.py            — FastAPI: /health, /match, /api/match, /api/options
│   ├── models.py          — Contractor, MatchRequest, ScoreBreakdown
│   ├── data_loader.py     — чтение и валидация hackathon_dataset.csv
│   ├── matcher.py         — жёсткие фильтры + сборка excluded{}
│   ├── relevance.py       — детерминированный скоринг (budget/confidence/relevance)
│   ├── frontend_api.py    — адаптер /match → контракт /api/match
│   ├── intent_parser.py   — опционально: Groq извлекает метки из query
│   ├── llm_explainer.py   — опционально: Groq переписывает текст объяснений
│   ├── conftest.py, test_*.py   — 95 тестов
│   └── __init__.py
│
├── frontend
│   ├── index.html         — форма запроса + переключатель демо-режима
│   ├── app.js              — fetch к API, рендер карточек, сравнение дат, воронка отсева
│   ├── mock.js              — готовые ответы для демо-режима (без бэкенда)
│   └── style.css
│
├── data
│   └── hackathon_dataset.csv   — 66 профилей подрядчиков
│
├── docs
│   ├── api.md              — контракт frontend ↔ backend, обе схемы (/match и /api/match)
│   └── task.md              — условие кейса (копия из Google Doc организаторов)
│
├── screenshots              — реальные скриншоты живого прогона (см. выше)
│
├── requirements.txt, pytest.ini, .env.example
└── README.md

API

Полный контракт — docs/api.md. Кратко для /api/match (то, что реально использует фронтенд):

POST /api/match

POST /api/match
Content-Type: application/json
{
  "city": "Алматы",
  "date": "2026-11-14",
  "event_type": "свадьба",
  "category": "Ведущий",
  "budget_kzt": 2000000,
  "hours": 5,
  "language": "казахский"
}

Ответ (status: found):

{
  "status": "found",
  "message": "Подходят только 2 из 8 кандидатов: остальные заняты в эту дату — 2, не работают с этим форматом — 4.",
  "cards": [
    {
      "id": "HK-16628",
      "name": "Нобара Кугисаки",
      "category": "Фотограф",
      "city": "Алматы",
      "price_from_kzt": 600000,
      "synthetic": false,
      "explanation": "Свободен 15.10.2026; цена от 600 000 ₸ при бюджете 2 000 000 ₸; работает на мероприятиях формата «корпоратив»; в описании упоминается: фотограф.",
      "alternative": false
    }
  ],
  "excluded": {
    "busy_on_date": 2,
    "over_budget": 0,
    "wrong_format": 4,
    "wrong_language": 0,
    "too_few_hours": 0
  },
  "service_intent": null,
  "interpreted_intent": null
}

status принимает три значения: found (1-3 карточки), no_category (такой категории в этом городе нет вообще), none_fit (кандидаты есть, но никто не прошёл фильтры). excluded считается среди кандидатов нужного города и категории и мутуально исключающе: каждый отсеянный кандидат учтён ровно один раз, по первому нарушенному правилу — счётчики не задваиваются.

Заголовок ответа X-Explanations: llm | mixed | template показывает, использовал ли Groq для переписывания текста, и для скольких карточек.

GET /api/options

{"cities": [...], "categories": [...], "event_formats": [...], "languages": [...]}

Опционально по контракту — если недоступен, фронтенд использует захардкоженный список.

GET /health

{"status": "ok", "contractors_loaded": 66}

Данные

data/hackathon_dataset.csv — 66 профилей подрядчиков, партнёрский анонимизированный датасет.

КатегорияПрофилей
Ведущий15
Фотограф12
Банкетный зал8
Ресторан7
Остальные (Лайв-бэнд, Шоу-программа, Видеограф и т.д.)4-5
Флорист, Декоратор, Подарки и сувениры, Ведущий церемонии, Фото и видеобудки, Отель, Инструменталист3 каждая

Поле synthetic сохраняется на всём пути до карточки в ответе API. Демо-режим фронтенда (mock.js) уже включает один явно синтетический профиль («Тихиро Огино», Флорист) для показа редкой категории без зависимости от бэкенда — с честной пометкой synthetic: true.


Детерминизм и устойчивость

Требование условия задачиКак реализовано
Один и тот же запрос → один и тот же порядок карточекСортировка (score desc, id asc); /api/match доказанно даёт те же первые 3 id, что и /match для эквивалентного запроса
AI не меняет состав/порядок/фильтрыGroq трогает только текст explanation уже выбранных карточек; проверено тестами test_llm_explainer.py, test_service_intent.py
Разные даты → разная выдача, видно, что дело в занятостиexcluded.busy_on_date явно показывает причину; UI показывает обе даты бок о бок
Категория-площадка — тот же пайплайн, без спецкейса«Банкетный зал» и подобные проходят через тот же matcher.py, что и любая другая категория
Демо не должно зависеть от доступности внешнего APIБез GROQ_API_KEY или при ENABLE_LLM_EXPLANATIONS=false — работает полностью детерминированно; фронтенд дополнительно умеет работать вовсе без бэкенда (демо-режим)
Невалидный ввод обрабатывается, а не роняет сервис422 на некорректную дату, бюджет ≤ 0, duration_hours ≤ 0, limit вне диапазона — покрыто тестами

Тесты

pip install -r requirements.txt
pytest

95 тестов, ни один не требует реального GROQ_API_KEY — Groq-зависимости подменяются на None/фейки через FastAPI dependency injection (get_explainer, get_intent_parser), поэтому тесты быстрые (~30 секунд) и не зависят от сети или квоты:

  • test_matcher.py, test_api.py — фильтры, скоринг, детерминизм, 422 на невалидный ввод
  • test_frontend_api.py — /api/match даёт ровно первые 3 результата /match в том же порядке, excluded-контракт
  • test_intent_parser.py, test_llm_explainer.py, test_service_intent.py — опциональные Groq-слои никогда не меняют состав/порядок карточек, валидация вывода (только известные id, без выдуманных фактов), fallback на любую ошибку
  • test_options.py — форма GET /api/options, согласованность с тем, что реально принимает /api/match

Воспроизводимость проверена вручную: установка зависимостей + pytest в чистом окружении → всё зелёное без ручного вмешательства.


Install & Run

Backend

pip install -r requirements.txt
cp .env.example .env        # опционально: вписать свой GROQ_API_KEY
uvicorn backend.main:app --reload

Backend поднимется на:

http://localhost:8000

Swagger: http://localhost:8000/docs.

Без GROQ_API_KEY (или при ENABLE_LLM_EXPLANATIONS=false/ENABLE_LLM_INTENT=false) сервис работает полностью детерминированно — разбора свободного текста и переписывания объяснений не будет, поведение фильтров и ранжирования не меняется.

Environment Variables

ПеременнаяОбязательнаПо умолчаниюЧто делает
GROQ_API_KEYНет— (пусто)Без ключа оба AI-слоя выключены; сервис работает полностью детерминированно
ENABLE_LLM_EXPLANATIONSНетtrue в .env.example; нужен ключРазрешает Groq переписывать текст объяснения (слой 2)
ENABLE_LLM_INTENTНетнаследует ENABLE_LLM_EXPLANATIONSРазрешает Groq разбирать свободный текст запроса (слой 1)
GROQ_MODELНетopenai/gpt-oss-120bМодель для обоих AI-слоёв
GROQ_TIMEOUT_SНет8Таймаут на вызов Groq; при превышении — детерминированный fallback, а не ошибка

Полный список с комментариями — в .env.example.

Frontend

cd frontend
python -m http.server 5500

Открыть http://localhost:5500. Backend должен быть уже запущен на :8000 (CORS открыт, allow_origins=["*"]).

Можно и без бэкенда вообще — включить «Демо-режим» переключателем в правом верхнем углу: все 5 обязательных по заданию сценариев отвечают из frontend/mock.js мгновенно.


Соответствие критериям оценки

Критерий (из условия задачи)БаллыЧто в проекте это покрывает
Соответствие задаче и работоспособность25Все 3 статуса, excluded всегда, детерминизм, площадки как обычная категория, 422 на невалидный ввод
Техническая реализация25Чёткое разделение слоёв (детерминированный движок отдельно от опциональных AI-слоёв), dependency injection для тестируемости без сети, валидация LLM-вывода против датасета, fallback на каждом AI-зависимом шаге
README и воспроизводимость25Этот файл: архитектура с диаграммой, контракт, данные, запуск, тесты, реальные скриншоты — весь путь пройден с чистой установкой зависимостей
Ценность и применимость решения15Объяснения строятся из реальных полей подрядчика; демо-режим убирает риск сетевого сбоя на самой презентации; воронка отсева и подсказки при no_category реально помогают пользователю, а не просто показывают отказ
Потенциал развития и оригинальность10Разбор намерения из свободного текста (service_intent, interpreted_intent) как расширяемый, но безопасный (валидируемый) AI-слой поверх детерминированного ядра; архитектурный выбор обоснован литературой, а не интуицией — см. docs/literature-review.md и таблицу сравнения с прежними работами

Известные ограничения

  • Без GROQ_API_KEY объяснения — детерминированный шаблон, а не естественный текст (см. заголовок X-Explanations в каждом ответе).
  • Нет бронирования, заявок или уведомлений подрядчику — только рекомендация, согласно условию задачи.
  • Нет сложного UI сверх формы и карточек результата — согласно прямому указанию в условии («если выбирать между интерфейсом и качеством объяснений — берите объяснения»).

Бизнес-модель

Глобальный рынок свадебных/event-услуг оценивается в $1,016.6 млрд в 2025 с прогнозом роста до $2,993.63 млрд к 2034 (CAGR 12.75%), при этом на Азиатско-Тихоокеанский регион приходится крупнейшая доля — 44% (Fortune Business Insights, 2025 — wedding services market report). Точных цифр по Казахстану в открытом доступе нет, но общий тренд (рост спроса на организованные, персонализированные event-услуги) — тот же самый, а площадка-агрегатор, о которой говорит кейс, подтверждает, что именно эта проблема (выбор из каталога) уже актуальна на локальном рынке.

Источник доходаКто платитМеханика
Комиссия за бронированиеПодрядчик% от суммы сделки после подтверждённого совпадения — начисляется, когда рекомендация приводит к реальному контракту
Платное продвижение в каталогеПодрядчикБолее высокий приоритет в ранжировании при прочих равных условиях (бюджет/дата/формат не нарушаются)
Подписка для агрегатора/организатораB2B-клиент (площадка, ивент-агентство)Доступ к API /api/match для встраивания в собственный сайт/CRM
Аналитика спросаПодрядчики и партнёры (Firebird)Агрегированная, обезличенная статистика: какие категории/бюджеты/города спрашивают чаще всего
СегментПотребностьПочему именно этот продукт
Заказчик мероприятияБыстро выбрать 1 из N подрядчиков без ручного сравненияОбъяснение на реальных фактах вместо голого списка
ПодрядчикПопасть в выдачу к релевантному заказчику, а не потеряться в каталогеЧестный none_fit с указанием причины — подрядчик понимает, что изменить, чтобы попадать в выдачу
Площадка-агрегатор (Firebird)Повысить конверсию каталога в бронирования без ручной модерацииГотовый матчинг-слой поверх уже существующего каталога, без переписывания его с нуля

Команда

Anomaly Detected · HackAlem AI 2026

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

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

Rahim Ahmed Druba 8Yermukassan 8SULDev2024 2

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

  • 2026-09-23 17:59Link demo video in READMERahim Ahmed Druba
  • 2026-09-23 17:57docs: add demo videoYermukassan
  • 2026-09-23 17:53Add business model tables, trilingual UI badgeRahim Ahmed Druba
  • 2026-09-23 17:51Add Technologies section, Environment Variables table, explicit Problem statementRahim Ahmed Druba
  • 2026-09-23 17:50fix: budget input accepts any value, i18n and style fixesYermukassan
  • 2026-09-23 17:45feat: RU/KZ/EN interface languagesYermukassan
  • 2026-09-23 17:45Trim literature review to fully-verified sources, add comparison table and two-AI-layers section to READMERahim Ahmed Druba
  • 2026-09-23 17:39Add literature review and related-work comparison tableRahim Ahmed Druba
Все коммиты (18)
  • 2026-09-23 17:37style: compact demo chips and calmer warning bannerYermukassan
  • 2026-09-23 17:27Add GET /api/options and refresh README/screenshots for the merged backendRahim Ahmed Druba
  • 2026-09-23 17:08style: redesign 4 result screens from design mockupsYermukassan
  • 2026-09-23 17:06Merge backend-deterministic-groq: deterministic matching backend with AI intent and explanationsSULDev2024
  • 2026-09-23 16:50Add deterministic contractor matching backend with AI intent and explanationsSULDev2024
  • 2026-09-23 16:37merge: keep new frontend, take teammate's READMEYermukassan
  • 2026-09-23 16:30Add frontend: matcher UI with explanations, transparency block, date comparison, mobile layoutYermukassan
  • 2026-09-23 16:19Rewrite README with architecture diagrams and real screenshotsRahim Ahmed Druba
  • 2026-09-23 15:51Implement contractor matching backend, frontend, and datasetRahim Ahmed Druba
  • 2026-09-23 15:17Add repo skeleton, API contract and README structureYermukassan
Структура репозитория (55 файлов)
.env.example
.gitignore
README.md
backend/.env.example
backend/__init__.py
backend/app/__init__.py
backend/app/config.py
backend/app/data_loader.py
backend/app/explain.py
backend/app/filters.py
backend/app/matcher.py
backend/app/ranking.py
backend/app/server.py
backend/conftest.py
backend/data_loader.py
backend/demo_queries.py
backend/frontend_api.py
backend/intent_parser.py
backend/llm_explainer.py
backend/main.py
backend/matcher.py
backend/models.py
backend/relevance.py
backend/requirements.txt
backend/test_api.py
backend/test_frontend_api.py
backend/test_intent_parser.py
backend/test_llm_explainer.py
backend/test_matcher.py
backend/test_options.py
backend/test_service_intent.py
backend/tests/__init__.py
backend/tests/test_determinism.py
backend/tests/test_explanations.py
backend/tests/test_filters.py
data/.gitkeep
data/hackathon-dataset-anonymized.jsonl
data/hackathon_dataset.csv
docs/api.md
docs/literature-review.md
docs/task.md
frontend/app.js
frontend/i18n.js
frontend/index.html
frontend/mock.js
frontend/style.css
pytest.ini
requirements.txt
screenshots/date-comparison.jpg
screenshots/form-empty.jpg
screenshots/found-results.jpg
screenshots/no-category-results.jpg
screenshots/none-fit-results.jpg
screenshots/transparency-panel.jpg
video/Untitled Project.mp4

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

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

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