Сервис приёма, нормализации и ИИ-обогащения данных об объектах недвижимости.
# 1. Клонировать и перейти в директорию cd vmk_data_collector # 2. Скопировать конфиг # Отредактируй .env под себя (OLLAMA_BASE_URL, порты и т.д.) cp .env.example .env # 3. Запуск всего стека (PostgreSQL + FastAPI) docker compose up -d --build # 4. Проверка # Документация API: http://localhost:8020/docs # Health check: http://localhost:8020/api/v1/health
docker compose down # остановить docker compose down -v # остановить + удалить данные БД
# 1. PostgreSQL должен быть доступен (локально или в Docker) # Порт по умолчанию: 5432 (хост) / 5433 (если через docker-compose) # 2. Установка зависимостей pip install -e ".[dev]" # 3. Применение миграций alembic upgrade head # 4. Запуск приложения uvicorn vmk_data_collector.main:app --reload --port 8020
POST /api/v1/ingestПринимает сырые данные от парсеров, валидирует payload и ставит задачу в очередь на обработку.
| Заголовок | Обязательный | Значение |
|---|---|---|
Content-Type |
Да | application/json |
{
"source_slug": "avito",
"external_id": "avito-12345678",
"payload": {
"title": "2-комнатная квартира, 65 м², 5/25 этаж",
"description": "Продается просторная двухкомнатная квартира в новостройке. Рядом метро.",
"price": 8500000,
"url": "https://avito.ru/item/12345678",
"images": [
"https://avito.ru/img1.jpg",
"https://avito.ru/img2.jpg"
],
"contact_phone": "+7 (999) 123-45-67",
"address": "Москва, Тверская ул., 1",
"area": 65.5,
"rooms": 2,
"floor": 5
}
}
payload| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
title |
string |
Нет | Заголовок объявления |
description |
string |
Нет | Описание объявления |
price |
number / string |
Нет | Цена (руб.) |
url |
string |
Нет | Ссылка на источник |
images |
string[] |
Нет | Массив URL изображений |
contact_phone |
string |
Нет | Телефон продавца |
address |
string |
Нет | Адрес объекта |
area |
number / string |
Нет | Площадь (м²) |
rooms |
integer / string |
Нет | Количество комнат |
floor |
integer / string |
Нет | Этаж |
Важно: хотя бы одно из полей title или description должно присутствовать.
202 Accepted (успех){
"job_id": 42,
"property_id": null,
"status": "pending",
"reason": null,
"message": "Queued for processing",
"snapshot_id": null
}
422 Unprocessable Entity (ошибка валидации){
"detail": "Invalid payload: 1 validation error for PayloadSchema..."
}
После приёма задача (job_id) проходит через pipeline:
| Статус | Значение |
|---|---|
pending |
Задача поставлена в очередь |
processing |
AI нормализует данные |
completed |
Объект сохранён в БД |
invalid |
AI определил, что это не недвижимость |
failed |
Ошибка на стадии обработки (Ollama недоступен и т.д.) |
curl -X POST http://localhost:8020/api/v1/ingest \
-H "Content-Type: application/json" \
-d '{
"source_slug": "avito",
"external_id": "avito-99999",
"payload": {
"title": "3-комнатная квартира, 120 м²",
"description": "Элитная квартира в центре",
"price": 25000000,
"url": "https://avito.ru/item/99999",
"address": "Москва, Сити"
}
}'
curl -X POST http://localhost:8020/api/v1/listings/1/archive-check
Все настройки задаются через переменные окружения (.env или docker-compose.yml):
| Переменная | Дефолт | Описание |
|---|---|---|
APP_PORT |
8020 |
Порт приложения (хост) |
DATABASE_URL |
postgresql+asyncpg://postgres:postgres@postgres:5432/vmk_data |
PostgreSQL (async) |
OLLAMA_BASE_URL |
http://192.168.1.75:11434 |
Ollama API |
OLLAMA_TEXT_MODEL |
gemma4:e2b-it-q4_K_M |
Модель для текстовых задач |
OLLAMA_VISION_MODEL |
gemma4:e2b-it-q4_K_M |
Модель для анализа изображений |
OLLAMA_TIMEOUT |
120 |
Таймаут запроса к Ollama (сек) |
LOG_LEVEL |
INFO |
Уровень логирования |
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Парсеры │────▶│ FastAPI │────▶│ PostgreSQL │
│ (curl/HTTP) │ │ /api/v1/ │ │ (raw_data + │
└──────────────┘ │ ingest │ │ property_...) │
└──────┬───────┘ └──────────────────┘
│
▼
┌──────────────┐
│ QueueWorker │
│ (async bg) │
└──────┬───────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│AI Норма-│ │AI Анализ│ │AI Обога-│
│лизатор │ │изображ. │ │щение │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└─────────────┴─────────────┘
│
▼
┌──────────────┐
│ Ollama │
│ 192.168.1.75 │
└──────────────┘
PropertyPipeline, AI-нормализация, обогащение, QueueWorkerhttp://localhost:8020/docshttp://localhost:8020/redocВсе логи выводятся в stdout в формате JSON (structlog), что удобно для сбора через docker compose logs:
# Следить за логами в реальном времени docker compose logs -f app # Посмотреть последние 50 строк docker compose logs --tail=50 app
Ключевые события для мониторинга:
ingest_request — новый запрос от парсераingest_accepted — задача поставлена в очередьingest_validation_failed — ошибка валидации payloadpipeline_start — начало обработки задачиpipeline_completed — задача успешно завершенаpipeline_not_real_estate — AI отбросил объектollama_chat_request/response — запросы к Ollama