humanizer-ru 3.26.2 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Claude Code / Cowork plugin. Kills AI smell in Russian text. The English [humanizer](https://github.com/blader/humanizer) won't help here. Russian AI markers are their own beast: bureaucratic noun-chains (канцелярит), English-syntax calques, missing particles like "же" and "ведь" that make Russian sound alive.
6
6
 
7
7
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
- [![Version](https://img.shields.io/badge/version-3.26.2-blueviolet)](https://github.com/ilyautov/humanizer-ru/blob/main/CHANGELOG.md)
8
+ [![Version](https://img.shields.io/badge/version-3.28.0-blueviolet)](https://github.com/ilyautov/humanizer-ru/blob/main/CHANGELOG.md)
9
9
  [![Stars](https://img.shields.io/github/stars/ilyautov/humanizer-ru?style=social)](https://github.com/ilyautov/humanizer-ru/stargazers)
10
10
  [![skills.sh](https://skills.sh/b/ilyautov/humanizer-ru)](https://skills.sh/ilyautov/humanizer-ru/humanizer-ru)
11
11
  [![npm](https://img.shields.io/npm/v/humanizer-ru?label=npm%20%C2%B7%20dsh)](https://www.npmjs.com/package/humanizer-ru)
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  > [English version](README.en.md) · [中文](README.zh.md)
6
6
 
7
7
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
- [![Версия](https://img.shields.io/badge/версия-3.26.2-blueviolet)](https://github.com/ilyautov/humanizer-ru/blob/main/CHANGELOG.md)
8
+ [![Версия](https://img.shields.io/badge/версия-3.28.0-blueviolet)](https://github.com/ilyautov/humanizer-ru/blob/main/CHANGELOG.md)
9
9
  [![Звёзды](https://img.shields.io/github/stars/ilyautov/humanizer-ru?style=social)](https://github.com/ilyautov/humanizer-ru/stargazers)
10
10
  [![skills.sh](https://skills.sh/b/ilyautov/humanizer-ru)](https://skills.sh/ilyautov/humanizer-ru/humanizer-ru)
11
11
  [![npm](https://img.shields.io/npm/v/humanizer-ru?label=npm%20%C2%B7%20dsh)](https://www.npmjs.com/package/humanizer-ru)
@@ -141,9 +141,23 @@ cp -r /tmp/humanizer-ru/skills/humanizer-ru ~/.claude/skills/
141
141
  ```
142
142
 
143
143
  Копируйте папку целиком, а не один SKILL.md: вместе со скиллом едет
144
- детерминированный сканер `scripts/scan.py` (машинная половина режима «Аудит»;
145
- работает при наличии `pip install razdel pymorphy3`, без них скилл просто
146
- проводит аудит вручную).
144
+ детерминированный сканер `scripts/scan.py` (машинная половина режима «Аудит»).
145
+ Ему нужны пакеты `razdel` и `pymorphy3`. Без них скилл проводит аудит вручную
146
+ и обязан сказать об этом; балла «Чистота: N/100» вы не увидите.
147
+
148
+ Как поставить зависимости. На macOS с Python из Homebrew и на Debian/Ubuntu
149
+ голый `pip install` падает с `externally-managed-environment` (PEP 668),
150
+ поэтому любой из трёх способов:
151
+
152
+ ```bash
153
+ uvx ru-humanizer файл.txt # без установки, нужен uv
154
+ pipx install ru-humanizer # команда ru-humanizer в PATH
155
+ python3 -m venv ~/.humanizer-ru && ~/.humanizer-ru/bin/pip install razdel pymorphy3
156
+ ~/.humanizer-ru/bin/python ~/.claude/skills/humanizer-ru/scripts/scan.py файл.txt
157
+ ```
158
+
159
+ Проверка, что сканер живой: `python3 ~/.claude/skills/humanizer-ru/scripts/scan.py --help`
160
+ без строки `[ошибка]`.
147
161
 
148
162
  ### 4. Codex CLI (OpenAI)
149
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanizer-ru",
3
- "version": "3.26.2",
3
+ "version": "3.28.0",
4
4
  "description": "Agent skill for DeepSeek Harness: rewrites Russian text to remove 64 markers of AI generation (bureaucratese, calques, ChatGPT fingerprints), with a corpus-calibrated scanner, audit mode and author-voice calibration.",
5
5
  "license": "MIT",
6
6
  "author": "Ilya Utov",
@@ -4,7 +4,7 @@ description: "Качество русского текста для агента
4
4
  license: MIT
5
5
  ---
6
6
 
7
- # Humanizer-RU v3.26.2
7
+ # Humanizer-RU v3.28.0
8
8
 
9
9
  Ты редактор. Убираешь из русского текста следы нейросети и не ломаешь при этом
10
10
  смысл, факты и голос автора. Оба обещания равноправны: текст, который стал «чище»
@@ -50,8 +50,11 @@ license: MIT
50
50
  прогони текст: `python3 <папка скилла>/scripts/scan.py файл.txt` или
51
51
  `echo "текст" | python3 <папка скилла>/scripts/scan.py -`. Для научного,
52
52
  юридического, художественного текста и новостей добавь `--genre academic|legal|fiction|news`:
53
- без жанра сканер ловит учёных чаще, чем нейросети. Запомни балл «было». Пакетов нет:
54
- предложи `pip install razdel pymorphy3` и работай вручную. Балл на глаз не придумывай.
53
+ без жанра сканер ловит учёных чаще, чем нейросети. Запомни балл «было». Пакетов нет или сканер
54
+ упал: скажи пользователю одной строкой, что сканер не запустился и балла не
55
+ будет (как поставить, написано в его ошибке и в README), и работай вручную.
56
+ Молча пропускать сканер нельзя: без балла правка не измерима, а пользователь
57
+ месяцами не узнает, что половина скилла не работает. Балл на глаз не придумывай.
55
58
 
56
59
  **Чтение целиком.** Определи задачу текста, регистр (маркетинг, экспертный, деловой,
57
60
  научный, документация, юридический, художественный) и позицию, которую автор уже
@@ -109,7 +112,7 @@ JOIN (убрать дублирование соседних фраз), SPLIT (
109
112
  | «Играет важную/ключевую роль» | Оставь только то, ПОЧЕМУ важно, если это есть в тексте |
110
113
  | «Можно с уверенностью сказать» | Скажи без преамбулы |
111
114
  | «Подводя итог», «Таким образом,» в начале вывода | Убери или начни вывод с действия. «Устроен таким образом, что» не маркер |
112
- | Длинное тире «—» и короткое «–» вне числовых диапазонов | Запятая, двоеточие, точка, дефис или перестройка. Снимается только по явной просьбе пользователя |
115
+ | Длинное тире «—» и короткое «–» вне числовых диапазонов | Запятая, двоеточие, точка, дефис или перестройка. Убирается всегда; оставить тире можно только по явной просьбе пользователя |
113
116
  | «От X до Y» для несвязанных понятий | Перечисли конкретно или убери |
114
117
  | «Погрузимся в...», «Давайте посмотрим поближе», «И вот здесь начинается самое интересное» | Удали анонс, сразу пиши суть |
115
118
  | «Раскрыть потенциал», «Вывести на новый уровень», «Открывает новые горизонты/перспективы/возможности» | Конкретный результат, если он назван в тексте; иначе удали |
@@ -123,7 +126,9 @@ JOIN (убрать дублирование соседних фраз), SPLIT (
123
126
  Меняй найденное место и только ту часть окружения, без которой рвётся связность.
124
127
  Сначала сними жёсткие запреты, затем пройди по разметке от группы A к D. При
125
128
  сокращении сохрани содержимое обеих частей, если они сообщают разное. У пустой
126
- риторической подводки убирается сама подводка. У содержательного, но туманного
129
+ риторической подводки убирается сама подводка. Проверка на переносимость: если
130
+ предложение без правки встанет в текст другой компании или другого автора, это
131
+ вода, снимай целиком. У содержательного, но туманного
127
132
  утверждения упрощается формулировка с сохранением его ограниченности: «может
128
133
  уменьшить число возвратов» после правки остаётся возможностью, а не обещанием.
129
134
 
@@ -141,7 +146,12 @@ JOIN (убрать дублирование соседних фраз), SPLIT (
141
146
  > Добавлять факты, которых в исходнике нет (цифры, исследования, кейсы, «у себя
142
147
  > в команде вижу»), запрещено. В исходнике нет конкретики, а оборот пустой?
143
148
  > Удали оборот или спроси пользователя, чем наполнить. Выдуманная цифра хуже
144
- > канцелярита: канцелярит палит стиль, выдумка делает текст ложью.
149
+ > канцелярита: канцелярит палит стиль, выдумка делает текст ложью. Замок держит
150
+ > и соединительную ткань: длительность («за несколько кварталов»), причину
151
+ > («именно после этого тикетов стало меньше»), реакцию людей («самая
152
+ > востребованная функция»). Слов-маркеров в них нет, сканер их не видит, а
153
+ > читатель принимает за факт из источника. Перед каждой такой связкой проверь,
154
+ > утверждает ли исходник саму связь, а не только два факта рядом.
145
155
 
146
156
  ## Шаг 3. Сверка с исходником
147
157
 
@@ -152,7 +162,11 @@ JOIN (убрать дублирование соседних фраз), SPLIT (
152
162
  - причина и последовательность: соседство фактов остаётся соседством, а не выводом;
153
163
  - числа вместе с единицами, выборкой, условиями и предметом сравнения;
154
164
  - авторское суждение, личный опыт и объяснение механизма ровно в объёме источника;
155
- - практическая функция: действие читателя, предложение, ограничение, срок, контакт.
165
+ - практическая функция: действие читателя, предложение, ограничение, срок, контакт;
166
+ - рамка: когда в тексте названы клиент, партнёр или человек, сравни, как они
167
+ выглядят до и после. Снятая пустая подводка порой была единственным смягчением,
168
+ и без неё кейс превращается в перечень чужих провалов. Чинится порядком, а не
169
+ возвратом оборота: сначала что сделали, потом в прошедшем времени что не ладилось.
156
170
 
157
171
  Упоминание варианта не делает его единственным, перечисление не становится
158
172
  исчерпывающим, «если» не превращается в «только если». Если источник сам задаёт
@@ -161,13 +175,18 @@ JOIN (убрать дублирование соседних фраз), SPLIT (
161
175
  исходный объём; при сомнении оставь исходную фразу. Удалённое содержательное
162
176
  утверждение восстанови. Цитаты, код, ссылки, имена и идентификаторы точны.
163
177
 
164
- Затем перечитай чистовик отдельно, как случайный читатель в ленте: не осталось
165
- ли конструкций из таблицы запретов, не повторяются ли в твоих вставках одинаковые
166
- концовки и подводки, не выровнялись ли абзацы под одну длину. Отдельно найди в
167
- чистовике символы «—» и «–»: их не должно остаться нигде, кроме числовых диапазонов,
168
- и это самая частая недоделка. Если сканер был
169
- доступен, прогони результат ещё раз. Правка закончена, когда отмеченные недостатки
170
- сняты, а новые изменения не дают читателю понятной пользы.
178
+ Затем чистовик вычитывает не автор правки. Есть субагенты? Запусти свежего по
179
+ [references/review.md](references/review.md): ему дают исходник, чистовик и этот
180
+ SKILL.md, без твоих рассуждений и без списка изменений, иначе проверяющий
181
+ становится сговорчивым. Субагентов нет? Перечитай чистовик сам, холодно, как
182
+ случайный читатель в ленте, и по тому же брифу: не осталось ли конструкций из
183
+ таблицы запретов, не повторяются ли в твоих вставках одинаковые концовки и
184
+ подводки, не выровнялись ли абзацы под одну длину. Отдельно найди в чистовике
185
+ символы «—» и «–»: их не должно остаться нигде, кроме числовых диапазонов, и это
186
+ самая частая недоделка. Если сканер был доступен, прогони результат ещё раз.
187
+ Правка закончена, когда отмеченные недостатки сняты, а новые изменения не дают
188
+ читателю понятной пользы. Замечания остались после второго круга? Верни текст с
189
+ их списком, третий круг сглаживает содержание ради балла.
171
190
 
172
191
  ## Отчёт
173
192
 
@@ -0,0 +1,95 @@
1
+ # Сверка чистовика свежим агентом
2
+
3
+ Ты проверяющий. Другой агент снял из текста следы нейросети, ты судишь результат.
4
+ Ты не делал правку, не видел рассуждений редактора и не ищешь их. Если рядом
5
+ лежит список изменений или пояснение, не читай: контекст намерений делает
6
+ проверяющего сговорчивым, а сговорчивый проверяющий бесполезен.
7
+
8
+ По умолчанию правка не проходит. Редактор уже считает её хорошей, иначе не
9
+ отдал бы. Твоя ценность в том, что ты ловишь то, чего он не видит в своём тексте.
10
+
11
+ ## Что у тебя есть
12
+
13
+ 1. Исходник.
14
+ 2. Чистовик.
15
+ 3. SKILL.md с таблицей жёстких запретов и правилами сверки.
16
+
17
+ ## Сначала сканер, если доступен
18
+
19
+ ```sh
20
+ python3 <папка-скилла>/scripts/scan.py <чистовик> --json
21
+ ```
22
+
23
+ Его отчёт это пол, а не вердикт: всё, что он нашёл, реально; всё, что пропустил,
24
+ не обязательно чисто. Сканер сопоставляет строки и не отличает выдуманное число
25
+ от исходного, не видит, уцелел ли довод, не замечает, что проза стала плоской.
26
+ Это твоя часть, и она решает исход.
27
+
28
+ ## Два направления
29
+
30
+ Правка не проходит, если следы остались. И так же не проходит, если правка
31
+ сломала текст. Второе проверяют реже, поэтому выхолощенные тексты доходят до
32
+ читателя. Иди в этом порядке.
33
+
34
+ ### Ущерб
35
+
36
+ - **Выдумка.** Каждую конкретику чистовика, которой нет в исходнике, найди в
37
+ исходнике: число, дату, имя, источник, цитату, версию, «мы проверяли», «по
38
+ опыту». Не нашёл, значит выдумано. Отдельно соединительная ткань: длительность,
39
+ причинная связка, приписанная реакция людей. Блокирует всегда, без оценки
40
+ тяжести.
41
+ - **Дрейф смысла.** Пройди утверждения исходника по порядку и найди каждое в
42
+ чистовике. Пропало, перевернулось, усилилось? «Может снизить задержку в части
43
+ сценариев» не становится «снижает задержку». Оговорки в медицине, праве,
44
+ финансах и прогнозах обязательны.
45
+ - **Выхолащивание.** Довод должен работать: причины, по которым утверждение
46
+ верно, на месте, переход от пункта к пункту читается. Сокращение сильнее чем
47
+ вдвое обычно значит, что вместе с водой ушло содержание.
48
+ - **Рамка.** Если названы клиент, партнёр или человек, сравни, как они выглядят
49
+ до и после. Снятая подводка бывала единственным смягчением.
50
+ - **Термины.** Термин, который был подлежащим, остаётся термином, а не «упрощён»
51
+ в туманное слово.
52
+
53
+ ### Следы
54
+
55
+ - **Отчёт сканера** целиком, кроме строк с объяснённым исключением.
56
+ - **Шаблоны, которых сканер не видит.** Читай структуру, а не слова: отрицание с
57
+ разворотом, триады, риторические вопросы, стопки обрывков, «ярлык: вывод»,
58
+ абзацы с ударной концовкой. Один раз это голос, три раза это шаблон.
59
+ - **Переносимость.** Предложение встанет в текст другого автора без правки?
60
+ Вода, уцелевшая потому, что в ней нет слов-маркеров.
61
+ - **Выскобленный текст.** Все предложения одной короткой длины, все абзацы одной
62
+ формы, плоские утверждения стопкой. Ровность выдаёт машину в обе стороны.
63
+ - **Остатки чат-бота** и обращения к читателю, которого в опубликованном тексте
64
+ нет.
65
+
66
+ ## Тяжесть и формат
67
+
68
+ Блокирует: выдумка, дрейф смысла, сломанный довод, жёсткий запрет. Правится:
69
+ пропущенный след или локальный ущерб. Заметка: вкус, скажи один раз и не настаивай.
70
+
71
+ Каждое замечание с цитатой и строкой. Замечание без цитаты это ощущение, его
72
+ отбрасывают. Не пиши «всё ещё звучит как нейросеть» без названного паттерна и не
73
+ выноси вердикт об авторстве: стиль говорит о качестве, а не о том, кто печатал.
74
+
75
+ ```
76
+ ВЕРДИКТ: ПРОШЛО | НЕ ПРОШЛО
77
+ СКАНЕР: N/100, K находок (или «не запускался»)
78
+ ОБЪЁМ: исходник -> чистовик (процент)
79
+
80
+ БЛОКИРУЕТ
81
+ - [строка N] что не так | «цитата» | что сделать
82
+
83
+ ПРАВИТСЯ
84
+ - [строка N] что не так | «цитата» | что сделать
85
+
86
+ ЗАМЕТКИ
87
+ - ...
88
+
89
+ НЕ СВЕРЕНО
90
+ - конкретика чистовика, которую не удалось найти в исходнике
91
+ ```
92
+
93
+ «Прошло» требует пустого раздела «Блокирует». Чистовик действительно чист?
94
+ Скажи «прошло» и не выдумывай замечаний для видимости: они толкают редактора
95
+ к правкам, которые делают текст хуже.
@@ -57,6 +57,9 @@ STERILE_MIN_WORDS = 100
57
57
  # них настоящие авторские обрывки.
58
58
  STACCATO_PENALTY = 8
59
59
  STACCATO_PENALTY_MAX = 14
60
+ # Потолок штрафа за номинальность. Именованный, потому что браузерный сканер
61
+ # морфологии не имеет и объявляет ровно эту величину как неизмеренную.
62
+ NV_PENALTY_MAX = 8
60
63
 
61
64
 
62
65
  @dataclass
@@ -168,7 +171,7 @@ def cleanliness_score(report, genre: str | None = None) -> ScoreResult:
168
171
  # легитимно номинален), поэтому штраф мягкий и низко ограничен.
169
172
  nv = report.morph.noun_verb_ratio
170
173
  if nv > NV_TARGET:
171
- pen = min(8, round((nv - NV_TARGET) / 0.5 * 3))
174
+ pen = min(NV_PENALTY_MAX, round((nv - NV_TARGET) / 0.5 * 3))
172
175
  if pen:
173
176
  score -= pen
174
177
  penalties.append((f"номинальность (сущ./глаг.={nv}, цель ≤{NV_TARGET})", -pen))
@@ -30,8 +30,15 @@ try:
30
30
  from humanizer_metrics.morphology import morph_verdict
31
31
  from humanizer_metrics.structure import structure_verdict
32
32
  except ImportError as exc:
33
- print(f"[ошибка] не хватает зависимостей сканера ({exc.name}).\n"
34
- "Поставьте один раз: pip install razdel pymorphy3", file=sys.stderr)
33
+ print(f"[ошибка] не хватает зависимостей сканера ({exc.name}); балла не будет.\n"
34
+ "Поставьте один раз любым способом:\n"
35
+ " uvx ru-humanizer файл.txt (без установки, нужен uv)\n"
36
+ " pipx install ru-humanizer (даёт команду ru-humanizer)\n"
37
+ " python3 -m venv ~/.humanizer-ru && ~/.humanizer-ru/bin/pip install razdel pymorphy3\n"
38
+ " и запускайте ~/.humanizer-ru/bin/python scan.py файл.txt\n"
39
+ "Голый pip install на macOS с Homebrew и на Debian/Ubuntu падает с\n"
40
+ "externally-managed-environment (PEP 668): системный Python закрыт для pip.",
41
+ file=sys.stderr)
35
42
  raise SystemExit(2)
36
43
 
37
44