# krrkt

Проверка качества русского текста в информационном стиле.

krrkt анализирует текст по двум слоям: быстрый словарный (1210 паттернов) и глубокий LLM-анализ (Claude). Оценивает по шкале от 0 до 10, совместимой с Главредом.

## Установка

```bash
pip install krrkt
```

Требуется Python 3.11+.

## Быстрый старт

### Проверить текст

```bash
krrkt check "Наша компания является лидером рынка и предлагает широкий спектр услуг."
```

Результат:

```
  3.6 / 10  ███░░░░░░░
  10 words, 1 sentences

  4 stop-words:
  ■ «является» Слабый глагол — Замените на обычный глагол
  ■ «лидером рынка» Корпоративный штамп — Приведите доказательства
  ■ «широкий спектр» Корпоративный штамп — У конкурентов написано то же самое
  ■ «услуг» Корпоративный штамп — Расскажите конкретнее
```

### Проверить файл

```bash
krrkt check ./article.txt
```

### Получить только балл

```bash
krrkt score "Завод выпускает подшипники."
# 9.5/10
```

## Режимы работы

### Быстрый (без LLM)

Анализирует текст по словарю из 1210 паттернов. Работает мгновенно, не требует API-ключа.

```bash
krrkt check "текст" --no-llm
```

### Полный (с LLM)

Сначала словарный анализ, потом Claude проверяет контекст, синтаксис и тональность. Находит то, что пропустил словарь.

```bash
krrkt check "текст"
```

Для полного режима нужен один из вариантов:
- **Claude Agent SDK** (подписка Claude) -- работает без API-ключа
- **Anthropic API** -- задайте переменную `ANTHROPIC_API_KEY`

```bash
export ANTHROPIC_API_KEY="sk-ant-..."
krrkt check "текст"
```

### Выбор модели

```bash
krrkt check "текст" --model claude-sonnet-4-6
```

По умолчанию используется `claude-sonnet-4-6`.

## Формат вывода

### Для человека (по умолчанию)

```bash
krrkt check "текст"
```

Три уровня серьёзности:
- `■` -- серьёзная проблема (weight >= 80)
- `▲` -- замечание (weight 1-79)
- `○` -- информационное (weight = 0)

### JSON

```bash
krrkt check "текст" --format json
```

```json
{
  "score": 3.6,
  "score_color": "red",
  "words": 10,
  "sentences": 1,
  "stopwords": 4,
  "findings": [
    {
      "start": 19,
      "end": 27,
      "word": "является",
      "rule": "Слабый глагол",
      "description": "Замените на обычный глагол",
      "weight": 50,
      "style": "orange",
      "tab": "red",
      "source": "fast"
    }
  ],
  "summary": {
    "Слабый глагол": 1,
    "Корпоративный штамп": 3
  }
}
```

## HTTP API

Запуск сервера:

```bash
krrkt serve --port 8080
```

### POST /api/v1/proofread

```bash
curl -X POST http://localhost:8080/api/v1/proofread \
  -H "Content-Type: application/json" \
  -d '{"text": "Текст для проверки", "skip_llm": true}'
```

### GET /api/v1/rules

Список всех категорий правил.

### GET /api/v1/health

Проверка работоспособности.

## Python API

```python
import asyncio
from krrkt.engine.pipeline import proofread

async def main():
    result = await proofread(
        "Наша компания является лидером рынка.",
        skip_llm=True  # без LLM
    )
    print(f"Балл: {result.score}/10")
    for f in result.findings:
        if f.weight > 0:
            print(f"  «{f.word}» -- {f.rule}")

asyncio.run(main())
```

### Поля результата

`ProofreadResult`:
| Поле | Тип | Описание |
|------|-----|----------|
| `score` | float | Балл 0-10 |
| `score_color` | str | green/orange/red |
| `words` | int | Количество слов |
| `sentences` | int | Количество предложений |
| `findings` | list | Список находок |
| `stopwords` | int | Стоп-слова (weight > 0) |
| `summary` | dict | Количество по категориям |

`Finding`:
| Поле | Тип | Описание |
|------|-----|----------|
| `start` | int | Начало в тексте (символ) |
| `end` | int | Конец в тексте (символ) |
| `word` | str | Найденное слово/фраза |
| `rule` | str | Категория правила |
| `description` | str | Рекомендация |
| `weight` | int | Серьёзность 0-100 |
| `style` | str | red/orange/blue |
| `tab` | str | red (чистота) / blue (читаемость) |
| `source` | str | fast / deep |

## Категории правил

krrkt проверяет текст по 39 категориям, разделённым на две вкладки.

### Чистота (tab: red)

| Категория | Вес | Пример |
|-----------|-----|--------|
| Корпоративный штамп | 100 | широкий спектр, команда профессионалов |
| Необъективная оценка | 100 | уникальный, инновационный, лучший |
| Усилитель | 100 | очень, абсолютно, невероятно |
| Паразит времени | 100 | на сегодняшний день, в настоящее время |
| Газетный штамп | 100 | ни для кого не секрет, семимильными шагами |
| Рекламный штамп | 100 | уникальное предложение, индивидуальный подход |
| Канцеляризм | 100 | в связи с, данный, осуществлять |
| Плеоназм | 100 | бесплатный подарок, главная суть |
| Неопределённость | 100 | некоторые, многолетний опыт |
| Обобщение | 100 | все, каждый, никогда |
| Заумное слово | 50 | коммуникация, инициировать, пролонгировать |
| Слово-паразит | 80 | просто, буквально, как бы |
| Отглагольное существительное | 80 | осуществлять поставку (= поставлять) |
| Модальный глагол | 80 | необходимо отметить (= отметим) |
| Слабый глагол | 50 | является, представляет собой, имеет |

### Читаемость (tab: blue)

| Категория | Вес | Пример |
|-----------|-----|--------|
| Вводная конструкция | 50 | безусловно, конечно, казалось бы |
| Сложный синтаксис | 80 | для того чтобы, несмотря на то что |
| Страдательный залог | 50 | было принято решение (= решили) |
| Причастие | 50 | длинные причастные обороты |
| Деепричастие | 50 | замените на глагол |
| Риторический вопрос | 50 | избегайте в информационном тексте |
| Восклицание | 50 | множественные ! |

## Шкала оценки

Формула: `floor((1 - взвешенные_стопслова / всего_слов)^3 * 100) / 10`

| Балл | Цвет | Значение |
|------|------|----------|
| 7.5-10 | зелёный | Чистый текст |
| 5-7.4 | оранжевый | Есть замечания |
| 0-4.9 | красный | Серьёзные проблемы |

Каждое найденное стоп-слово вносит вклад `weight / 100` в формулу. Слово с weight=100 считается за полное стоп-слово, с weight=50 -- за половину.

## Архитектура

```
Текст
  |
  v
Fast Layer (мгновенно)
  |-- Фразы: точное совпадение подстрок (682 паттерна)
  |-- Леммы: морфологический анализ pymorphy3 (510 паттернов)
  |-- Морфология: причастия, деепричастия (POS-теги)
  |-- Regex: структурные паттерны (18 правил)
  |
  v
Deep Layer (Claude LLM, опционально)
  |-- Получает текст + уже найденные проблемы
  |-- Анализирует контекст, синтаксис, тональность
  |-- Находит то, что словарь пропустил
  |
  v
Merge + Score
  |-- Объединяет находки, убирает дубли
  |-- Считает балл по кубической формуле
  |
  v
Результат (score + findings)
```

## Конфигурация

Все файлы конфигурации в `config/`:

| Файл | Назначение |
|------|------------|
| `patterns.yaml` | Словарь паттернов (фразы, леммы, regex) |
| `rules.yaml` | Категории правил с описаниями |
| `config.yaml` | Настройки сервера и скоринга |
| `prompts/analyze.yaml` | Системный промпт для Deep Layer |

### Добавить паттерн

Фраза (точное совпадение):
```yaml
phrases:
  - pattern: "новая фраза"
    rule: "Корпоративный штамп"
    weight: 100
    style: red
    tab: red
```

Лемма (морфологическое совпадение):
```yaml
lemmas:
  - lemma: "слово"
    rule: "Необъективная оценка"
    weight: 100
    style: red
    tab: red
```

## Разработка

```bash
git clone <repo>
cd glvrd-reverse
pip install -e ".[dev]"
```

### Тесты

```bash
pytest tests/unit/          # юнит-тесты
pytest tests/e2e/           # golden-тесты на примерах из книги
pytest tests/ -m llm        # тесты с LLM (нужен API-ключ)
```

### Сравнение с Главредом

```bash
python compare_with_glvrd.py
```

Текущие метрики (v1.5, 1210 паттернов):
- Средняя разница: 0.27
- Точное совпадение: 80%
- Близкое (diff <= 1): 89%
- Допустимое (diff <= 2): 94%

## Лицензия

MIT
