SmartMatch
Сервис подбора подрядчиков для мероприятия по описанию на русском: извлекает условия, фильтрует каталог из 66 профилей, ранжирует и показывает до…
О проекте
Команда: ChezaurodynaHackathone
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Сервис подбора подрядчиков для мероприятия по описанию на русском: извлекает условия, фильтрует каталог из 66 профилей, ранжирует и показывает до трёх кандидатов с объяснением выбора и причинами исключения остальных.
Как устроено
brief.py (или OpenAI) разбирает свободное описание в поля: город, категория, дата, бюджет, формат, язык, длительность; пользователь их проверяет. hard_filter.py применяет жёсткие ограничения и сохраняет причины отказа. engine.py считает взвешенный балл: соответствие описанию 34% (LLM или локальный текстовый индекс), бюджет 30%, язык 12%, длительность 10%, происхождение данных 14%. Затем весь допустимый список сортируется и берутся первые три. Объяснения сервер собирает из фактов профиля и проверенной цитаты. Запросы, результаты и отмеченные кандидаты сохраняются в SQLite.
Ключевые решения
- hard filtering
- weighted scoring
- local text index
- LLM brief extraction
- response validation
- in-memory LRU cache
Особенности
LLM видит только профили, прошедшие фильтры, и не может снять ограничение или поменять цену. Бюджетная эвристика максимальна, когда стартовая цена около 72% верхней границы бюджета. Различаются три исхода: кандидаты есть; категория есть, но никто не подходит; категории нет. Синтетические профили и профили с восстановленными полями помечены и слегка штрафуются.
Стек
Python 3.11 · http.server · sqlite3 · HTML/CSS/JS · Docker · GitHub Actions
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-38743673-chezaurodynahackathone.
README
README.mdSmartMatch — MVP подбора подрядчиков
1. Что делает проект
SmartMatch подбирает подрядчика для мероприятия по описанию на русском языке. Пользователь описывает задачу, проверяет заполненные условия и получает до трёх профилей из каталога HackAlem AI. Система объясняет выбор фактами из профиля и показывает причины исключения остальных кандидатов.
2. Что реализовано
- Адаптивный сайт: описание, редактируемые параметры, примеры, карточки и подробности отбора.
- Единая цепочка: разбор описания → проверка параметров → фильтры → ранжирование → объяснения → сохранение в SQLite.
- Фильтры по городу, категории, дате, диапазону стартовой цены, формату, языку, длительности и происхождению профиля.
- Сортировка по соответствию, возрастанию или убыванию цены. Сначала сортируются все допустимые кандидаты, затем выбираются первые три.
- Серверное подключение OpenAI с проверкой ответа и локальным режимом при отсутствии ключа или ошибке API.
- Постоянная база каталога, истории поисков и отмеченных кандидатов.
- Три исхода: кандидаты найдены; категория есть, но никто не подходит; категории нет в городе.
- Общий пакет
smartmatch/, автоматические тесты, единая конфигурация и архив ранних прототипов.
3. Технологии и архитектура
Python 3.11+, стандартные библиотеки http.server, sqlite3, urllib, unittest; HTML, CSS и JavaScript без сборщика. Сторонние Python-пакеты для запуска не нужны. SQLite встроена в Python: отдельный сервер базы данных не требуется.
Браузер: HTML / CSS / JavaScript
↓ HTTP JSON
web.py → service.py: общий сценарий приложения
├─ brief.py: извлечение условий
├─ models.py: проверка запроса
├─ database.py + repository.py: каталог
└─ hard_filter.py → engine.py: фильтры → оценка → сортировка
↕ ai.py: модель и проверка ответа
↓
SQLite: запрос, снимок результата, выбор кандидата
ИИ получает только прошедшие фильтры профили. Он не может отменить ограничение, изменить цену или добавить подрядчика вне каталога. Объяснения собираются сервером из фактов и подтверждённой цитаты.
4. Порядок установки и запуска
- Установите Python 3.11+. В Windows включите добавление Python в
PATH. - Скачайте репозиторий либо клонируйте его с доступом к репозиторию команды.
- Откройте терминал в папке, где находится
run.py, и выполните:
python run.py --open-browser
В Linux/macOS команда может называться python3. В Windows также можно открыть Запустить SmartMatch.cmd двойным щелчком. Адрес сайта: http://127.0.0.1:8000. Терминал сервера оставьте открытым; Ctrl+C останавливает сервер.
При первом запуске создаётся runtime/smartmatch.sqlite3 и импортируется каталог. Без ключа доступны форма, фильтры, сортировка, локальный разбор и запись истории. ИИ подключается по инструкции ниже.
Двойной щелчок по smartmatch/static/index.html показывает оформление, но не запускает API, поиск или базу. Для полноценной работы используйте HTTP-адрес.
5. Пример проверки
Нажмите «Посмотреть на примере» — это локальный подбор без расходов API. Либо введите:
Нужен ведущий на корпоратив в Алматы 6 октября 2026 года. Бюджет до 1 млн тенге, русский язык, 5 часов. Интеллигентная подача для бизнес-аудитории, без навязчивых конкурсов.
Нажмите «Заполнить по описанию», проверьте форму, затем «Найти подрядчиков». Для исходного каталога, минимальной цены 0 и включённых синтетических профилей ожидаются 6 подходящих профилей, показаны 3. В карточках есть объяснение, язык, стартовая цена и календарь. Отметка кандидата сохраняется в БД и не является бронированием.
Автоматическая проверка без ключа:
python -m unittest discover -s tests -v
python scripts/evaluate.py
6. Используемые данные и внешние сервисы
Рабочий источник — data/contractors.csv: 66 анонимизированных профилей, из них 53 исходных и 13 синтетических. У 8 записей восстановлен город, у 18 — цена; метки сохранены в БД и видны на сайте. «Исходный» означает происхождение из предоставленного каталога, а не независимую проверку подрядчика.
OpenAI — необязательный сервис извлечения условий и оценки соответствия описаний. В коде по умолчанию задана модель gpt-4.1-mini; её можно заменить настройкой. Доступность, стоимость и ограничения зависят от вашего API-проекта. При отключённом ИИ внешних запросов нет.
SQLite сохраняет условия и пожелания, снимок ответа, фактический режим ИИ и отмеченных кандидатов. Подробности — в разделе базы данных.
7. Известные ограничения
- Календарь: 23.09.2026–31.12.2026. Даты вне периода не принимаются; данные не обновляются автоматически.
- Цена «от» не является коммерческим предложением. Диапазон бюджета сравнивается со стартовой ценой; окончательную стоимость нужно подтвердить.
- Отсутствие занятой даты в выборке не гарантирует актуальную доступность. Нет оплаты, контактов, сообщений или бронирования.
- У 9 строк
max_hoursне задан. В MVP это отсутствие применимого ограничения: такой профиль не исключается по длительности; время нужно подтвердить отдельно. - Форма поддерживает один обязательный язык. Запрос «русский и казахский» считается неоднозначным: выберите основной язык вручную; требование владеть обоими одновременно пока не реализовано.
- Локальный текстовый поиск хуже понимает смысл и отрицания, чем языковая модель. Балл не является вероятностью успешного мероприятия.
- Проверка цитат и ID не доказывает качество подрядчика. Распознанные условия пользователь подтверждает вручную.
- Встроенный HTTP-сервер предназначен для локальной демонстрации и хакатона. Публичное размещение требует HTTPS, контроля доступа, лимитов API и правил хранения пользовательских данных.
- Нет аккаунтов, административного редактора каталога, автоматического обучения на истории и многосерверной синхронизации.
8. Развёрнутая версия
Публичная версия пока не развёрнута. После запуска: http://127.0.0.1:8000. Текущий рабочий просмотр может использовать порт 8010. Оба адреса локальные: они не открывают сайт на компьютерах других участников сами по себе.
Работа с формой и фильтрами
- Укажите, кто нужен, город, полную дату с годом, формат и бюджет в тенге. Язык и длительность необязательны.
- Выполните разбор описания. Недостающие или неоднозначные условия не подставляются автоматически.
- Проверьте поля. Ручные изменения имеют приоритет при следующем разборе. Если текст ещё не разобран, первое нажатие поиска заполнит поля для проверки, второе выполнит подбор.
- Задайте минимальную цену, происхождение профилей и сортировку при необходимости.
- Получите карточки; раскройте «Как прошёл отбор» для причин исключения.
- Отметьте подходящих кандидатов: это сигнал интереса в истории, без отправки сообщения или бронирования.
После изменения условий предыдущий список помечается как устаревший — выполните поиск снова. Один профиль может не пройти несколько условий, поэтому сумма причин отказа может превышать число исключённых кандидатов.
| Параметр | Правило |
|---|---|
| Город, категория | Совпадение с каталогом без учёта регистра; у профиля возможны несколько категорий |
| Дата | В пределах календаря и отсутствует в занятых датах |
| Максимальный бюджет | Целое число 1–1 000 000 000 ₸; стартовая цена не выше |
| Минимальная цена | Целое число от 0 до максимального бюджета; стартовая цена не ниже |
| Формат | Входит в поддерживаемые форматы |
| Язык | Если выбран, входит в языки профиля; пустое значение — любой |
| Длительность | В форме 0,5–24 часа с шагом 0,5; API принимает любое конечное число больше 0 и не выше 24; не превышает заданный max_hours |
| Синтетические профили | При отключении исключаются все строки с synthetic=true |
| Пожелания | Влияют на оценку текста, не отменяют условия формы |
Некорректные строки CSV изолируются до подбора. Метаданные содержат число и причины таких записей. Пустой корректный каталог останавливает запуск с ошибкой.
Оценка и сортировка
| Компонент | Вес |
|---|---|
| Соответствие описания: ИИ или локальный текстовый индекс | 34% |
| Соответствие бюджету | 30% |
| Язык | 12% |
| Длительность | 10% |
| Происхождение и восстановленные данные | 14% |
Бюджетная эвристика достигает максимума при стартовой цене около 72% верхнего бюджета. Это выбранная формула, а не доказательство качества услуги. Синтетическое происхождение и восстановленные цена/город немного снижают составляющую качества данных. Формула находится в smartmatch/engine.py.
relevance сортирует по итоговому баллу, price_asc — по возрастанию цены, price_desc — по убыванию. При равенстве используется ID. Сортировка по цене может показать других кандидатов: она применяется ко всему допустимому списку до ограничения в три карточки.
Локальный режим воспроизводим при неизменных запросе и каталоге. Успешные ответы ИИ кэшируются в памяти (128 записей); одинаковые параллельные запросы синхронизированы. После перезапуска или вытеснения из кэша оценка модели может измениться. SQLite хранит прошлый результат, но не служит постоянным кэшем модели.
Настройка OpenAI
Создайте .env рядом с run.py на основе .env.example, не перезаписывая уже заполненный файл.
PowerShell:
if (-not (Test-Path .env)) { Copy-Item .env.example .env }
notepad .env
Linux/macOS:
test -f .env || cp .env.example .env
Впишите ключ после OPENAI_API_KEY= только в локальном .env:
SMARTMATCH_AI_PROVIDER=openai
SMARTMATCH_AI_MODEL=gpt-4.1-mini
OPENAI_API_KEY=
SMARTMATCH_AI_TIMEOUT=8
Сохраните файл и перезапустите сервер. Переменные окружения имеют приоритет над .env. Статус «OpenAI настроен» подтверждает конфигурацию, а не успешный вызов. Реальная проверка — подбор с включённым ИИ; поле ответа ai.used показывает, использовалась ли модель для ранжирования.
.env исключён из Git и Docker-образа. Не вставляйте ключ в HTML, JavaScript, README или .env.example. На хостинге задайте OPENAI_API_KEY в переменных окружения сервиса.
Запросы модели
При разборе передаются описание пользователя и допустимые значения каталога. При ранжировании — условия заказа, анонимные ID и описания только прошедших фильтры подрядчиков. Не вводите в пожелания секреты или ненужные персональные данные: текст передаётся модели и сохраняется в локальной истории.
OpenAI-адаптер вызывает /v1/responses, задаёт JSON Schema и store: false. Сервер проверяет полноту списка, ID, оценки 0–100 и буквальное присутствие цитат в исходных описаниях. Извлечённые числа и даты должны подтверждаться фрагментами пользовательского текста. Ошибка API или неподтверждённый ответ заменяются локальным результатом с явным пояснением.
Одновременно разрешены два сетевых вызова. SMARTMATCH_AI_TIMEOUT — время ожидания одного вызова, 1–30 секунд, по умолчанию 8. Это не пользовательская квота расходов.
В коде также сохранены адаптеры gemini и compatible. Совместимому сервису нужны SMARTMATCH_AI_PROVIDER=compatible, SMARTMATCH_AI_MODEL, SMARTMATCH_AI_BASE_URL и SMARTMATCH_AI_API_KEY либо OPENAI_API_KEY; он должен поддерживать используемую JSON Schema. Для Gemini задаются SMARTMATCH_AI_PROVIDER=gemini и GEMINI_API_KEY. Тестовые ответы проверяют адаптеры, но не доказывают совместимость любого внешнего провайдера.
База данных и сбор информации
Рабочая база создаётся автоматически: runtime/smartmatch.sqlite3. При первом запуске CSV проверяется и импортируется одной транзакцией. Повторный запуск не дублирует и не перезаписывает каталог или историю. Изменение CSV не обновляет уже созданную БД автоматически. Для отдельного нового каталога задайте новый путь через --db; сервер загружает каталог при запуске, поэтому после изменения БД нужен перезапуск.
| Таблица | Содержимое |
|---|---|
profiles | Основные сведения, происхождение, цена, календарь |
profile_categories, profile_event_formats, profile_languages | Категории, форматы, языки |
profile_busy_dates | Занятые даты |
metadata, import_audit | Версия, первичный импорт, изолированные строки |
searches | Время UTC, нормализованный запрос, полный снимок ответа |
search_results | Показанные подрядчики и порядок карточек |
selections | Отметки кандидатов, привязанные к конкретному поиску |
У каждого поиска свой search_id. Сохраняются и поиски без результатов. Отметить можно только подрядчика, показанного в этом поиске. Повторная отметка той же пары не создаёт дубль; можно отметить несколько кандидатов. Система не определяет реального заказчика и не объединяет его действия между поисками.
Ключи API, IP-адреса и отпечатки браузера в таблицы не записываются. Веб-сервер ведёт обычный консольный журнал запросов, в котором присутствует сетевой адрес клиента. Текст пожеланий хранится как введён пользователем; автоматического удаления или обезличивания свободного текста нет.
База использует внешние ключи, транзакции, режим WAL и отдельное соединение для каждой операции. Запись истории — часть запроса: при недоступном хранилище сервер возвращает ошибку вместо ложного сообщения «сохранено». История не доступна через публичный HTTP-маршрут: выгрузку делает оператор локально.
Инициализация и выгрузка
Создать базу без запуска сайта или посмотреть количество записей:
python scripts/init_database.py
python scripts/init_database.py --db runtime/catalog-test.sqlite3 --csv data/contractors.csv
Выгрузить запросы, результаты и выбор кандидатов в UTF-8 JSON:
python scripts/export_history.py --output exports/history.json
Для другого файла базы добавьте --db путь/к/базе.sqlite3. Экспорт содержит текст пользовательских пожеланий; храните его с теми же ограничениями доступа, что и БД. Команда отказывается перезаписывать существующий файл: для повторной выгрузки задайте новое имя, например exports/history-2026-09-24.json.
Дополнительные синтетические профили
По умолчанию генерация отключена: каталог содержит ровно 66 предоставленных записей. Для отдельного теста можно создать другой каталог:
python scripts/init_database.py --db runtime/synthetic-demo.sqlite3 --generate 30
python run.py --db runtime/synthetic-demo.sqlite3 --port 8011
Получится 96 записей: 53 исходных, 13 синтетических из CSV и 30 новых тестовых. Генератор использует фиксированный seed и явные правила data/synthetic_profile_rules.json, не обращается к ИИ и помечает добавленные записи как синтетические. Другой файл правил задаётся --rules; допустимое количество — 0–10 000. Повторение той же генерации пропускает совпадающие ID, конфликтующие данные откатывают новую партию. Это число запрашиваемых образцов, а не команда уменьшения каталога; --generate 0 не удаляет уже добавленные записи. После изменения БД перезапустите сервер.
Файлы *.sqlite3, их журналы и папка exports/ исключены из Git. Перед переносом БД остановите сервер; для работающей базы используйте SQLite Backup API, а не копирование одного файла без WAL. Политики сроков хранения и удаления пользовательских запросов в MVP ещё нет.
HTTP API
POST-запросам нужен Content-Type: application/json; тело ограничено 32 768 байтами. API принимает описание и пожелания длиной не более 6000 символов; поле описания на сайте ограничено 5000. Неверные типы, бесконечные числа, некорректная дата или диапазон цены отклоняются.
| Маршрут | Назначение |
|---|---|
GET /api/health | Доступность сервера и БД |
GET /api/meta | Варианты фильтров, календарь, качество каталога, статус ИИ без ключа |
POST /api/parse-brief | Извлечение редактируемых условий |
POST /api/recommend | Подбор и запись поиска |
POST /api/selection | Отметка кандидата из конкретной выдачи |
Для /api/parse-brief:
{
"description": "Нужен ведущий на корпоратив в Алматы 6 октября 2026 года, до 1 млн тенге, 5 часов, русский язык.",
"use_ai": false
}
Ответ: query, missing_fields, warnings, mode, message. Сам разбор не создаёт подбор и не бронирует услугу.
Для /api/recommend:
{
"city": "Алматы",
"event_date": "2026-10-06",
"event_format": "корпоратив",
"category": "Ведущий",
"budget_kzt": 1000000,
"min_budget_kzt": 0,
"language": "русский",
"duration_hours": 5,
"preferences": "Интеллигентная подача для бизнес-аудитории",
"include_synthetic": true,
"sort_by": "relevance",
"use_ai": false
}
status: success, no_eligible или no_market. results — карточки; pipeline — количество после каждого этапа; exclusions и rejected_candidates — причины отказа; eligible_count — число всех допустимых профилей; ai.used — фактический режим. search_id и saved: true подтверждают запись истории.
Сохраните показанный JSON в request.json. PowerShell:
$body = [System.IO.File]::ReadAllText((Resolve-Path request.json))
$result = Invoke-RestMethod 'http://127.0.0.1:8000/api/recommend' -Method Post -ContentType 'application/json; charset=utf-8' -Body ([System.Text.Encoding]::UTF8.GetBytes($body))
$result | ConvertTo-Json -Depth 10
Linux/macOS:
curl -s http://127.0.0.1:8000/api/recommend -H 'Content-Type: application/json' --data-binary @request.json
Для /api/selection подставьте search_id и ID из его results:
{"search_id": "ID_полученного_поиска", "contractor_id": "ID_показанного_подрядчика"}
Успешный ответ — {"saved": true, "created": true}; повторная отметка возвращает created: false. Неизвестная пара отклоняется. Проверка принадлежности карточки поиску не заменяет авторизацию пользователя: для публичного сервиса её нужно добавить.
Параметры запуска и Docker
python run.py --host 127.0.0.1 --port 8010 --open-browser
python run.py --data data/contractors.csv --db runtime/smartmatch.sqlite3
python run.py --help
По умолчанию --host 127.0.0.1, --port 8000. Для демонстрации в локальной сети используйте --host 0.0.0.0, затем IP-адрес компьютера. Участникам нужен сетевой доступ к этой машине.
Docker Compose:
docker compose up --build -d
docker compose logs -f smartmatch
docker compose down
Откройте http://127.0.0.1:8000. По умолчанию порт контейнера доступен только на локальном компьютере. Compose подставляет OpenAI-настройки из .env и сохраняет SQLite в именованном томе smartmatch-data, путь контейнера — /var/lib/smartmatch/smartmatch.sqlite3. Обычный docker compose down оставляет том. Не используйте down -v, если нужно сохранить собранные данные.
Вариант без Compose:
docker build -t smartmatch .
docker run --rm -p 127.0.0.1:8000:8000 --env-file .env -v smartmatch-data:/var/lib/smartmatch smartmatch python run.py --host 0.0.0.0 --port 8000 --db /var/lib/smartmatch/smartmatch.sqlite3
Для локального режима без файла настроек уберите --env-file .env. Сам контейнер не делает сайт публичным сервисом с HTTPS и авторизацией.
Проверки и диагностика
python -m unittest discover -s tests -v
python scripts/evaluate.py
Тесты покрывают фильтры и сортировку, границы значений, разбор текста, цитаты и ID, кэш, ошибки модели, HTTP и SQLite. Тестовый транспорт не обращается к API. scripts/evaluate.py выводит JSON со сценариями, временем и 100 повторами локального запроса; проверяйте all_checks_passed. Время зависит от машины.
Проверена работа локального сайта, фильтров и сохранения отметки в SQLite. Живой вызов OpenAI с действующим ключом и запуск контейнера Docker в текущей проверке не выполнялись; подготовленная конфигурация не означает, что они уже проверены в вашей среде.
| Условия, ИИ выключен | Результат исходной выборки |
|---|---|
| Алматы / Ведущий / 06.10.2026 / корпоратив / до 1 млн / русский / 5 ч | 6 допустимых, 3 карточки |
| Алматы / Флорист / 04.10.2026 / свадьба / до 500 тыс. / русский | 2 карточки |
| Алматы / Флорист / 01.10.2026 / свадьба / до 500 тыс. / русский | no_eligible |
| Астана / Декоратор / 04.10.2026 / свадьба / до 1 млн / русский | no_market |
Во всех примерах минимальная цена — 0, синтетические профили включены. После изменения каталога числа могут измениться.
| Проблема | Решение |
|---|---|
| HTML открылся, кнопки не работают | Запустите сервер и откройте HTTP-адрес |
python не найден | Установите Python 3.11+; попробуйте py -3 в Windows или python3 в Linux/macOS |
| Порт занят | Остановите старый запуск или укажите другой --port |
| ИИ не включается | Проверьте файл .env рядом с run.py, затем перезапустите сервер |
| ИИ настроен, но ответ локальный | Проверьте доступ к модели, ключ, лимиты, сеть; возможен тайм-аут или отклонение ответа при валидации |
| Нет кандидатов | Откройте причины исключения, проверьте диапазон цены, дату, длительность и остальные условия |
| База недоступна | Проверьте доступ на запись в папку --db и целостность файла |
| CSV изменён, а каталог прежний | Импорт выполняется один раз; используйте отдельную новую БД или осознанную миграцию |
| CSS изменён, а автономный HTML прежний | Выполните python scripts/embed_styles.py и обновите страницу |
Структура репозитория и анализ кода
run.py Единая точка запуска
Запустить SmartMatch.cmd Запуск для Windows
README.md Общий гайд
.env.example Пустой пример серверной конфигурации
Dockerfile, compose.yaml Контейнер и постоянный том
smartmatch/
web.py, service.py HTTP и общий сценарий приложения
models.py Типы и проверка параметров
repository.py Импорт и проверка CSV
database.py, schema.sql SQLite, история и выбор
hard_filter.py Жёсткие условия
engine.py Оценка, сортировка, объяснения
ai.py, brief.py, text.py ИИ, разбор и локальный индекс
samples.py Общие демонстрационные запросы
generate_profiles.py Необязательные синтетические образцы
static/ HTML, CSS, JavaScript, значок
data/contractors.csv Исходные 66 профилей
data/synthetic_profile_rules.json Правила необязательной генерации
runtime/smartmatch.sqlite3 Создаётся локально, не входит в Git
scripts/ Проверки, обслуживание БД, обновление CSS
tests/ Тесты рабочего MVP
docs/CODE_REVIEW.md Анализ модулей и решений
archive/prototypes/ Исторические эксперименты команды
.github/workflows/tests.yml Автоматическая проверка
Прежние second-layer, third-layer и Database описывали разные модели, переменные AI_PROXY_*, точки запуска и каталог на 96 профилей. Они не образовывали единого сайта: третий этап зависел от модуля из другой папки, а некоторые файлы базы отсутствовали.
Рабочая цепочка теперь находится в smartmatch/ и использует общий .env. Отдельный генеративный запрос прототипа объяснений не выполняется: проверенные цитаты и факты объединяются в объяснение на сервере. Дополнительные 30 синтетических записей не смешиваются с исходными 66 автоматически.
Оригинальные эксперименты сохранены в archive/prototypes/ranking, explanations и database. Они не импортируются сервером. Исторические DESIGN_NOTES.md, API_SETUP.md и DATABASE_GUIDE.md сохраняют контекст команды; их команды и модели не являются инструкцией запуска MVP. Единственный актуальный README — этот файл. Подробный результат анализа — docs/CODE_REVIEW.md.
Исходник оформления — smartmatch/static/styles.css. Его копия встроена в HTML для просмотра оформления без сервера. После правок выполняйте python scripts/embed_styles.py, чтобы копии совпадали.
Авторы коммитов
История коммитов
- 2026-09-23 17:44Add UI design specifications for frontendyei48
- 2026-09-23 17:13Integrate SmartMatch MVP with unified filters, SQLite history and complete guideislamabdul
- 2026-09-23 16:44Explain standalone HTML styling and full application launchislamabdul
- 2026-09-23 16:44Add script to refresh embedded stylesheet from CSS sourceislamabdul
- 2026-09-23 16:44Keep SmartMatch styling when index.html is opened without adjacent assetsislamabdul
- 2026-09-23 16:36Add files via uploadDelta Greencheese
- 2026-09-23 16:33Create welp.txtDelta Greencheese
- 2026-09-23 16:21Preserve complete browser script and stabilize HTTP validation responsesislamabdul
Все коммиты (20)
- 2026-09-23 16:15Add files via uploadDelta Greencheese
- 2026-09-23 16:15Build description-first SmartMatch site with validated server-side OpenAI matchingislamabdul
- 2026-09-23 16:13Create help.txtDelta Greencheese
- 2026-09-23 15:56Add files via uploadDelta Greencheese
- 2026-09-23 15:56Create help.txtDelta Greencheese
- 2026-09-23 15:42Keep result cards scrollable within reference layoutislamabdul
- 2026-09-23 15:41Match SmartMatch UI to approved referenceislamabdul
- 2026-09-23 15:39Match SmartMatch UI to approved referenceislamabdul
- 2026-09-23 15:17Add strict hard-filter gate and rejection diagnosticsislamabdul
- 2026-09-23 14:40Added profile generator for test drive the systemDelta Greencheese
- 2026-09-23 14:38Build deterministic explainable contractor matcherislamabdul
- 2026-09-23 13:53Add project system filtering requirementsDelta Greencheese
Структура репозитория (68 файлов)
.dockerignore .editorconfig .env.example .gitattributes .github/workflows/tests.yml .gitignore Dockerfile README.md archive/original-plan.txt archive/prototypes/database/DATABASE_GUIDE.md archive/prototypes/database/DESIGN_NOTES.md archive/prototypes/database/contractors.csv archive/prototypes/database/generate_profiles.py archive/prototypes/database/init_database.py archive/prototypes/database/schema.sql archive/prototypes/database/synthetic_profile_rules.json archive/prototypes/database/test_profile_database.py archive/prototypes/database/welp.txt archive/prototypes/explanations/API_SETUP.md archive/prototypes/explanations/DESIGN_NOTES.md archive/prototypes/explanations/examples/selected_profiles.json archive/prototypes/explanations/help.txt archive/prototypes/explanations/profile_explanations.py archive/prototypes/explanations/set_test_key.ps1.example archive/prototypes/explanations/test_profile_explanations.py archive/prototypes/explanations/verify_profile_explanations.py archive/prototypes/ranking/DESIGN_NOTES.md archive/prototypes/ranking/help.txt archive/prototypes/ranking/set_test_key.ps1.example archive/prototypes/ranking/smartmatch.py archive/prototypes/ranking/test_smartmatch.py archive/prototypes/ranking/verify_openai_proxy.py compose.yaml data/contractors.csv data/synthetic_profile_rules.json design docs/CODE_REVIEW.md pyproject.toml requirements.txt run.py scripts/embed_styles.py scripts/evaluate.py scripts/export_history.py scripts/init_database.py smartmatch/__init__.py smartmatch/ai.py smartmatch/brief.py smartmatch/database.py smartmatch/engine.py smartmatch/generate_profiles.py smartmatch/hard_filter.py smartmatch/models.py smartmatch/repository.py smartmatch/samples.py smartmatch/schema.sql smartmatch/service.py smartmatch/static/app.js smartmatch/static/favicon.svg smartmatch/static/index.html smartmatch/static/styles.css smartmatch/text.py smartmatch/web.py tests/test_ai.py tests/test_database.py tests/test_engine.py tests/test_repository.py tests/test_web.py Запустить SmartMatch.cmd
Ветки (2)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.