🚀 Live Application (Render): https://avito-splitter.onrender.com
Локальный MVP для split одного объявления на несколько самостоятельных услуг. В проекте backend на FastAPI сохранен без изменений, а demo frontend переведен на Gradio и работает как thin client поверх POST /split.
- 🚀 Live Application (Render): https://avito-splitter.onrender.com
- rnc_test.csv - экспертный CSV с
159test-запросами и заполненной колонкойresponse - backend API на FastAPI с
POST /splitиGET /health - детерминированный split-pipeline без внешних API
- demo frontend на Gradio
- launcher-скрипты для локального и публичного demo
- regression, API, smoke и browser e2e тесты на
pytest+ Playwright - локальные данные и demo cases
- src/avito_splitter - API и доменная логика
- demo/gradio_app.py - Gradio demo UI
- demo/demo_cases.json - demo-кейсы
- data - runtime-каталог и eval-данные
- tests - unit, API, smoke и Playwright e2e
- run_project.py - основной launcher
- run_project.bat - thin wrapper над launcher
- start_demo.bat - быстрый запуск demo на Windows
Поток обработки:
- Gradio UI собирает payload объявления.
- Frontend отправляет HTTP-запрос в backend
POST /split. - Backend нормализует текст, находит микрокатегории и проверяет самостоятельность услуги.
- Pipeline возвращает
SplitResponse. - Gradio UI показывает verdict, drafts, raw JSON и сверку с эталоном demo-case.
Gradio не содержит split-логики. Он только загружает demo-cases и каталог микрокатегорий, вызывает backend и рендерит ответ.
Вход:
{
"itemId": 1002,
"mcId": 101,
"mcTitle": "Ремонт квартир и домов под ключ",
"description": "Отдельно выполняем сантехнические и электромонтажные работы."
}Выход:
{
"shouldSplit": true,
"drafts": [
{
"mcId": 102,
"mcTitle": "Сантехника",
"text": "..."
},
{
"mcId": 103,
"mcTitle": "Электрика",
"text": "..."
}
]
}Стабильные правила:
- backend API не менялся при миграции frontend
- исходный
mcIdне попадает вdrafts draftsвсегда список- порядок
draftsсоответствует порядку подтвержденных услуг в тексте
Минимально нужно:
Python 3.10+Git- локальный
Google Chromeдля Playwright smoke-test
Установка:
cd avito
python -m pip install --upgrade pip
python -m pip install -r requirements.txtВ requirements.txt demo frontend теперь зависит от gradio. streamlit больше не используется.
Самый короткий локальный запуск:
python run_project.pyИли на Windows:
run_project.batДля совсем быстрого локального старта demo:
start_demo.batLauncher поднимет:
- FastAPI backend
- локальный Gradio demo UI
Если порты заняты, launcher автоматически выберет следующие свободные порты и напечатает итоговые ссылки.
python run_project.py
python run_project.py demoЧто делает:
- поднимает backend
- поднимает локальный Gradio frontend
- ждет
GET /healthу backend иGET /у frontend - печатает локальные ссылки
python run_project.py publicЧто делает:
- поднимает backend
- поднимает Gradio с
share=True - печатает:
Local backend docs: ...Local demo UI: ...Public demo UI: https://2cb0fcbccca842137d.gradio.live
Важно:
publicбольше не используетngrok- публичная ссылка жива, пока жив процесс
- для долгого публичного хостинга нужен отдельный deploy
- если
share=Trueне смог поднять ссылку из-за сети или сервиса Gradio, это operational issue, а не дефект backend
python run_project.py backendpython run_project.py frontendПо умолчанию frontend использует backend http://127.0.0.1:8000.
Можно указать другой backend:
python run_project.py frontend --backend-url http://127.0.0.1:8100python run_project.py report
python run_project.py testBackend:
uvicorn src.avito_splitter.api:app --reloadFrontend:
python demo/gradio_app.pyRuntime env-переменные frontend:
AVITO_BACKEND_URLdefaulthttp://127.0.0.1:8000AVITO_GRADIO_SHAREdefaultfalseAVITO_GRADIO_SERVER_NAMEdefault127.0.0.1AVITO_GRADIO_SERVER_PORTdefault7860
Gradio demo поддерживает:
Backend URL- индикатор доступности backend
- dropdown
Demo-кейс - кнопку
Подставить кейс Item ID- dropdown
Микрокатегория - read-only preview
mcId - поле
Описание - кнопку
Обработать объявление - verdict по
shouldSplit - рендер draft-карточек
Raw JSON- сверку с эталоном demo-case
Основные demo-кейсы лежат в demo/demo_cases.json:
- комплексная услуга
- отдельные услуги
- перечисление услуг
- исключение исходной категории
- нейтральное упоминание
- смешанный контекст
- Без split:
Делаем ремонт под ключ, включая электрику и сантехнику.
Ожидание: shouldSplit = false
- Split на 2 услуги:
Отдельно выполняем сантехнические и электромонтажные работы.
Ожидание: shouldSplit = true, draftMcIds = [102, 103]
- Перечисление услуг:
Выполняем электрику, сантехнику, натяжные потолки.
Ожидание: shouldSplit = true, draftMcIds = [103, 102, 104]
Полный прогон:
pytestКлючевые наборы:
- backend unit и regression tests
- FastAPI API tests
- Gradio smoke tests
- Playwright browser e2e на живом backend/frontend
- launcher smoke tests
- expert dataset audit regression
Отдельно:
pytest tests/test_gradio_smoke.py
pytest tests/test_playwright_e2e.py
pytest tests/test_run_project_smoke.pyКороткий маршрут:
- Выполнить
python -m pip install -r requirements.txt - Выполнить
pytest - Выполнить
python run_project.py - Открыть demo UI
- Подставить demo-case
Отдельные услуги - Нажать
Обработать объявление - Проверить verdict, drafts и сверку с эталоном
- При необходимости открыть
/docs
- backend остается отдельным FastAPI сервисом
- frontend остается thin client поверх HTTP backend
share=Trueподходит для demo/hackathon, но не для постоянного продакшен-хостинга- два одновременно запущенных процесса
python run_project.py publicдолжны получить разныеgradio.liveссылки, если обе share-сессии успешно поднялись