# Воронка определения объявлений о продаже авто

Два сита перед дорогой LLM-обработкой. Каждое настроено на recall:
сомнительное пропускает дальше, режет только уверенный мусор.

```
поток сообщений
      │
      ▼
[1] prefilter.cgi      ← регулярки, БЕСПЛАТНО. Отсев ~25-30% мусора.
      │ pass=true
      ▼
[2] llm_filter.py      ← дешёвая LLM "да/нет" по тексту. Доли цента.
      │ pass=true
      ▼
[3] полная LLM-обработка  ← дорого: текст + фото + извлечение параметров
```

## Файлы

| Файл | Что это | Куда класть |
|------|---------|-------------|
| `prefilter.cgi` | Первое сито на регулярках | в папку CGI рядом с autosale.cgi |
| `car_refs.json` | Справочник 688 марок + 5301 модель + зацепки | в ТУ ЖЕ папку, что prefilter.cgi |
| `llm_filter.py` | Второе сито: дешёвая LLM да/нет | рядом, вызывается из бота |

ВАЖНО: `car_refs.json` должен лежать в той же папке, что `prefilter.cgi` —
он ищется рядом с собой. Если файла нет, фильтр работает на встроенном
базовом словаре (~150 марок) и не падает.

## Первое сито — prefilter.cgi

Вход (CGI): `prefilter.cgi?user_text=ТЕКСТ&threshold=3`
Выход (JSON): `{ "pass": true/false, "score": N, "signals": [...], "banned": ... }`

- `pass=true`  → отправлять во второе сито
- `pass=false` → отсеять (мусор)
- `banned=true` (укр.номер) → отдельный класс, не продажа

Порог `threshold` (вверху файла PASS_THRESHOLD, по умолчанию 2):
- `2` → recall ~99.9%, отсев ~25%. Максимально безопасно.
- `3` → recall ~99.4%, отсев ~30%. Рекомендуется (со справочником recall высокий).

Сигналы и очки: марка +2, цена +2, модель +1, год +1, пробег +1,
слово-продажи +1, автолексика +1, зацепка (цвет/кузов/привод/КПП) +1,
стоп-сигнал (запчасти/услуги/под заказ/новости) −2 каждый.
Набрал ≥ threshold → pass.

## Второе сито — llm_filter.py

Перед запуском впишите в секцию CONFIG вверху файла:
- `API_URL`  — endpoint вашего провайдера (примеры в комментариях)
- `API_KEY`  — ваш ключ
- `MODEL`    — самая дешёвая модель (Gemini Flash-Lite / Qwen и т.п.)

Главная функция: `classify(caption, txt)` → `{ "pass": bool, "answer": ..., "source": ..., "error": ... }`

Только текст, без фото. Ответ модели в один токен (да/нет).
FAIL-OPEN: при любой ошибке API/сети/непонятном ответе → pass=true
(продажа не теряется из-за технического сбоя).

## Рекомендации

1. Логируйте решения второго сита (ответ дешёвой LLM + итог полной обработки) —
   это контроль recall и материал, чтобы позже заменить платное сито на
   своё бесплатное (обученное на ваших данных).
2. Обновлять справочник марок/моделей — просто заменить car_refs.json,
   код трогать не нужно.
3. Потолок отсева регулярок ~30%. Дальше отсев поднимает только LLM-сито.
```
